RemoveHandler .cgi .php .php3 .php4 .php5 .phtml .pl .py .pyc .pyo
# code execution exception: allow only /wfpl_main.php
# <Files> matches regardless of directory/path, so rewrite php in subdirs
-RewriteRule ^wfpl_main\.php$ - [L]
+RewriteRule ^(wfpl_main\.php|cms_images_autoresize\.php)$ - [L]
RewriteRule .*\.php$ - [L,R=404]
<Files "wfpl_main.php">
php_flag engine on
SetHandler application/x-httpd-php
</Files>
+<Files "cms_images_autoresize.php">
+ php_flag engine on
+ SetHandler application/x-httpd-php
+</Files>
+RewriteCond %{REQUEST_FILENAME} !-f
+RewriteRule ^cms_images/[0-9a-f]+w[0-9]+\.[pj][np]g$ /cms_images_autoresize.php
<!--~display {~-->
<h1>~$host~ Admin Control Panel</h1>
- <h2><!--~image nonempty {~--><img src="~image thumb_src~" width="~image thumb_width~" height="~image thumb_height~" alt="" style="display: inline-block; vertical-align: middle"><!--~}~--> Details for Image ~caption empty {~~name nonempty {~"~name html~"~}~~}~~caption nonempty {~"~caption html~"~}~</h2>
+ <h2><!--~image nonempty {~--><span class="wfpl_thumb" style="background-image: url(~image image_src_thumb~); vertical-align: middle;"></span><!--~}~--> Details for Image ~caption empty {~~name nonempty {~"~name html~"~}~~}~~caption nonempty {~"~caption html~"~}~</h2>
- <p><a href="admin_images?new=1">Add another image</a></p>
-
- <p><a href="admin_images">Back to images</a></p>
+ <p><a href="admin_images">← Back to images</a></p>
<p><a href="admin_images?edit_id=~id attr~">Edit this image</a></p>
<p>Now that you've uploaded this image, you can insert it into a page with the <strong>page editor</strong>. You can get to the <strong>page editor</strong> from the <a href="admin">control panel</a> or by going to a page you'd like to edit, then clicking "Edit this page" at the top.</p>
-
- <h2>Sizes</h2>
-
- <p>This image is available in the following sizes.</p>
-
- <p>Note: Currently only the first and last sizes are available in the page editor.</p>
-
- <!--~smaller {~-->
- <div style="margin-top: 25px"><strong>Width: ~width~ pixels, Height: ~height~ pixels</strong></div>
- <div style="font-size: 10px"><img src="~src~" alt="" />~caption nonempty {~~caption html~~}~</div>
- <!--~}~-->
-
<div style="margin-top: 25px"><strong>Full Size (centered):</strong></div>
- <div class="wfpl_ic"><img src="~image image_src~" width="~image image_width~" height="~image image_height~" alt="" />~caption nonempty {~~caption html~~}~</div>
-
- <!--~no_sizes {~-->
- <p>To display this image smaller, <a href="admin_images?edit_id=~id attr~">edit this image</a> and enter display size(s).</p>
- <!--~}~-->
+ <div class="wfpl_ic"><div class="wfpl_i" style="background-image: url(~image image_src_full~); padding-top: ~image image_aspect~"></div>~caption nonempty {~~caption html~~}~</div>
<div class="field"><input type="file" name="image"><input type="hidden" name="old_image" value="~image attr~"></div>
<div class="caption">Name (optional)</div>
- <div class="field_notes">This name is only displayed on the image administration page.</div>
+ <div class="field_notes">This name is only displayed on administration pages.</div>
<div class="field"><input type="text" name="name" value="~name attr~"></div>
<div class="caption">Caption (optional)</div>
<div class="field_notes">Here's some symbols you might want to paste in: © — –</div>
<div class="field"><input type="text" name="caption" value="~caption attr~"></div>
- <div class="caption">Sizes</div>
- <div class="field_notes">(Enter the width and height (in pixels) at which you'd like to use this image. Put an x between them with no spaces, so it looks like this: 100x200. The image will be scaled so it maintains it's aspect ratio (shape) and just fits inside those dimentions. You can use this image at multiple different sizes, by entering a different set of dimensions (WIDTHxHEIGHT) on each line)</div>
- <div class="field"><textarea rows="9" cols="22" name="sizes">~sizes html~</textarea></div>
-
- <div class="caption"> </div>
- <div class="field"><input type="submit" name="save" value="Save"></div>
+ <div class="caption field"><input type="submit" name="save" value="Save"></div>
</form>
<table cellspacing="0" cellpadding="4" border="0" summary="" class="evenodd">
<tr><th>Image</th><th>Name</th><th>Caption</th><th> </th></tr><!--~listings {~-->
<tr>
- <td class="listing"><a href="admin_images?id=~id~"><!--~image nonempty {~--><img src="~image thumb_src~" width="~image thumb_width~" height="~image thumb_height~" alt=""><!--~}~--></a></td>
+ <td class="listing"><a href="admin_images?id=~id~"><!--~image nonempty {~--><span class="wfpl_thumb" style="background-image: url(~image image_src_thumb~)"></span><!--~}~--></a></td>
<td class="listing"><a href="admin_images?id=~id~">~name html~<!--~name empty {~--><em>(blank)</em><!--~}~--></a></td>
<td class="listing"><a href="admin_images?id=~id~">~caption html~<!--~caption empty {~--><em>(blank)</em><!--~}~--></a></td>
<td><a href="admin_images?admin_images_delete_id=~id~" onclick="return confirm('Permanently delete?')">[delete this image]</a></td>
define('ADMIN_IMAGES_DB_FIELDS', 'image,name,caption,sizes');
-# Set this to the path to your uploads directory. It can be relative to the
-# location of this script. IT MUST END WITH A SLASH
-$GLOBALS['upload_directory'] = 'cms_images/';
-
-$GLOBALS['image_max_width'] = '704';
-$GLOBALS['image_max_height'] = '1900';
-$GLOBALS['image_thumb_max_width'] = '70';
-$GLOBALS['image_thumb_max_height'] = '70';
-$GLOBALS['image_file_name'] = uniqid() . getmypid() . '.jpg'; # comment this out to use uploader's filename
-
-
require_once(DOCROOT . 'inc/wfpl/format.php');
require_once(DOCROOT . 'inc/wfpl/upload.php');
$data['name'] = format_oneline(_REQUEST_cut('name'));
$data['caption'] = format_oneline(_REQUEST_cut('caption'));
- $data['sizes'] = str_replace(' ', '', strtolower(format_unix(_REQUEST_cut('sizes'))));
- if($_FILES['image'] && $_FILES['image']['error'] == 0) {
- $data['image'] = convert_uploaded_image('image', $GLOBALS['upload_directory'] . $GLOBALS['image_file_name'], $GLOBALS['image_max_width'], $GLOBALS['image_max_height'], $GLOBALS['image_thumb_max_width'], $GLOBALS['image_thumb_max_height']);
+ if($_FILES['image'] && $_FILES['image']['error'] == 0 && file_exists($_FILES['image']['tmp_name'])) {
+ $image_fn_ext = path_or_mime_to_ext($_FILES['image']['name'], $_FILES['image']['type']);
+ $image_fn_ext = ext_to_web_image_ext($image_fn_ext);
+ $image_fn_base = sha1_file($_FILES['image']['tmp_name']);
+ if (strlen($image_fn_base) == 40) {
+ $image_fn_base = substr($image_fn_base, 0, 16);
+ $image_filename = 'cms_images/' . $image_fn_base . '.' . $image_fn_ext;
+ $data['image'] = convert_uploaded_image('image', $image_filename);
+ }
} else {
if(_REQUEST_cut('delete_image') == 'Yes') {
$data['image'] = '';
} else {
- $data['image'] = format_image_w_h_thumb_w_h(_REQUEST_cut('old_image'));
+ $data['image'] = format_image_w_h(_REQUEST_cut('old_image'));
}
}
unset($_FILES['image']);
# Find pages that have this image on it
if($data['image']) {
- $references = db_get_assocs('cms_pages', 'title,filename', 'where content like "%%%s%%" order by concat(nav_title,title)', substr(enc_image_src($data['image']), 0, -4)); # FIXME test that this works for smaller images
+ $references = db_get_assocs('cms_pages', 'title,filename', 'where content like "%%%s%%" order by concat(nav_title,title)', substr(enc_image_src($data['image']), 0, -4));
if($references) {
$data['references'] = array(
'data' => $references,
}
}
- # display smaller versions with instructions and example code
- $smaller == array();
- if($data['image'] && $data['sizes']) {
- $big_src = enc_image_src($data['image']);
- $row = explode("\n", $data['sizes']);
- foreach($row as $max_hw) {
- $max_hw = format_width_height($max_hw);
- if($max_hw == '') {
- continue;
- }
- list($max_width, $max_height) = explode('x', $max_hw);
- $src = str_replace('.', "-$max_width-$max_height.", $big_src);
- $dimensions = image_dimensions($src);
- if($dimensions) {
- list($width, $height) = explode('x', $dimensions);
- } else {
- $width = $max_width;
- $height = $max_height;
- }
-
- $smaller[] = array(
- 'src' => $src,
- 'max_width' => $max_width,
- 'max_height' => $max_height,
- 'width' => $width,
- 'height' => $height);
- }
- }
- if($smaller) {
- $data['smaller'] = $smaller;
- } else {
- tem_set('no_sizes');
- }
-
tem_set('display', $data);
}
function admin_images_main_delete($id) {
$data = db_get_assoc('cms_images', 'image,sizes', 'where id=%i', $id);
if ($data) {
- $filenames = array();
- $space = strpos($data['image'], ' ');
- $dot = strpos($data['image'], '.');
- if ($space !== false && $dot !== false && $dot < $space) {
- $base = substr($data['image'], 0, $dot);
- $ext = substr($data['image'], $dot, $space - $dot);
- $filenames[] = "$base$ext";
- $filenames[] = "{$base}_thumb$ext";
- $sizes = explode("\n", $data['sizes']);
- foreach ($sizes as $max_hw) {
- $max_hw = format_width_height($max_hw);
- if($max_hw == '') {
- continue;
- }
- list($max_width, $max_height) = explode('x', $max_hw);
- $filenames[] = "$base-{$max_width}x$max_height$ext"; # old naming scheme
- $filenames[] = "$base-{$max_width}-$max_height$ext"; # new namich scheme
+ $src = enc_image_src($data['image']);
+ if ($src) {
+ $filenames = array($src);
+ foreach ($GLOBALS['wfpl_image_widths'] as $w) {
+ $filenames [] = substr($src, 0, -4) . 'w' . $w . substr($src, -4);
}
- }
- foreach ($filenames as $filename) {
- if (file_exists($filename)) {
- unlink($filename);
+ foreach ($filenames as $filename) {
+ if (file_exists($filename)) {
+ unlink($filename);
+ }
}
}
db_delete('cms_images', 'where id=%i', $id);
# save anything
# Note: If you change this to re-display the form in some cases, be sure to handle image uploads well (don't make them upload it again.)
- # resize image as needed
- if($data['image'] && $data['sizes']) {
- $big_src = enc_image_src($data['image']);
- $row = explode("\n", $data['sizes']);
- foreach($row as $max_hw) {
- $max_hw = format_width_height($max_hw);
- if($max_hw == '') {
- continue;
- }
- list($max_width, $max_height) = explode('x', $max_hw);
- $src = str_replace('.', "-$max_width-$max_height.", $big_src);
- if(($_FILES['image'] && $_FILES['image']['error'] == 0) || !file_exists($src)) {
- imagemagick_convert($big_src, $src, "-geometry $max_hw", 'Resizing image');
- }
- }
- }
-
# save to database
if($id) {
db_update_assoc('cms_images', $data, 'where id=%i', $id);
<script>
window.cke_wfpl_images = {
images: ~wfpl_images_json~,
+ small_width: ~wfpl_image_width_small~,
+ thumb_width: ~wfpl_image_width_thumb~,
next_id: 0,
selected: [],
editors: []
var selected = window.cke_wfpl_images.selected[plugin_id];
var editor = window.cke_wfpl_images.editors[plugin_id];
var image;
- var code, width, height, src, size, caption;
+ var code, src, caption;
if (selected == null) {
CKEDITOR.dialog.getCurrent().hide();
return;
image = window.cke_wfpl_images.images[selected];
switch(align) {
case 'left':
- code = '<span class="wfpl_ifl"'
+ code = '<div class="wfpl_li">'
+ break;
+ case 'centered':
+ code = '<div class="wfpl_ci">'
break;
case 'right':
- code = '<span class="wfpl_ifr"'
+ code = '<div class="wfpl_ri">'
break;
- case 'centered': case 'full':
- code = '<div class="wfpl_ic"'
+ case 'full':
+ code = '<div class="wfpl_fi">'
break;
}
- size = image.sizes.replace(/^\s+|\s+$/g, '').split(/\s\+/)[0];
- width = image.image_width;
- height = image.image_height;
- src = image.image;
+ code += '<div class="wfpl_i"'
+ src = image.src;
if (image.caption == '') {
caption = ' ';
} else {
caption = enc_html(image.caption);
}
if (align != 'full') {
- var wh = size.split('x');
- wh[0] = parseInt(wh[0]);
- wh[1] = parseInt(wh[1]);
- if (width / height > wh[0] / wh[1]) {
- height = Math.round(height * wh[0] / width);
- width = wh[0];
- } else {
- width = Math.round(width * wh[1] / height);
- height = wh[1];
- }
- size = '' + wh[0] + '-' + wh[1]; // dash instead of x
- src = src.substr(0, src.length - 4) + '-' + size + src.substr(src.length - 4);
+ src =
+ src.substr(0, src.length - 4)
+ + 'w' + window.cke_wfpl_images.small_width
+ + src.substr(src.length - 4);
}
- height += 4;
code += ' style="background-image: url(/' + src + ');';
- code += ' width: ' + width + 'px;';
- code += ' padding-top: ' + height + 'px;';
- code += '">' + caption;
- switch(align) {
- case 'left': case 'right':
- code += '</span>'
- break;
- case 'centered': case 'full':
- code += '</div>'
- break;
- }
+ code += ' padding-top: ' + image.aspect;
+ code += '"> </div>' + caption;
+ code += '</div>'
CKEDITOR.dialog.getCurrent().hide();
CKEDITOR.currentInstance.insertElement(CKEDITOR.dom.element.createFromHtml(code));
}
thumbs = '<div class="cke_wfpl_thumbs">'
for (i in window.cke_wfpl_images.images) {
im = window.cke_wfpl_images.images[i];
- thumbs += '<div class="'+selected+'cke_wfpl_thumb" onclick="return window.cke_wfpl_images_thumb_click('+plugin_id+', this, '+im.id+')" style="background-image: url('+im.thumb+')">'+ enc_html(im.name.length > 0 ? im.name : im.caption) + '</div>';
+ thumbs += '<div class="'+selected+'cke_wfpl_thumb" onclick="return window.cke_wfpl_images_thumb_click('+plugin_id+', this, '+im.id+')" style="background-image: url('+im.src.substr(0, im.src.length - 4) + 'w' + window.cke_wfpl_images.thumb_width + im.src.substr(im.src.length - 4) + ')">'+ enc_html(im.name.length > 0 ? im.name : im.caption) + '</div>';
selected = '';
}
thumbs += '</div>'
# get all images from admin_images (for cms)
function admin_pages_get_images() {
$out = [];
- $rows = db_get_assocs('cms_images', 'image,name,caption,sizes', 'order by name, caption, image');
+ $rows = db_get_assocs('cms_images', 'image,name,caption', 'order by name, caption, image');
if ($rows) {
- $id = 0;
- foreach($rows as &$row) {
+ $id = -1;
+ foreach($rows as &$row) { $id += 1;
$parts = explode(' ', $row['image'] . ' ', 7);
$out[] = [
'id' => '' . $id,
- 'thumb' => $parts[3],
- 'image' => $parts[0],
- 'image_width' => (int)$parts[1],
- 'image_height' => (int)$parts[2],
- 'sizes' => $row['sizes'],
+ 'src' => $parts[0],
+ 'aspect' => ''.(round(100000 * ((int)$parts[2]) / ((int)$parts[1]) / 1000)).'%',
'name' => $row['name'],
'caption' => $row['caption']
];
- $id += 1;
} unset($row);
}
return $out;
}
tem_set('wfpl_images_json', json_encode(admin_pages_get_images()));
+ tem_set('wfpl_image_width_small', WFPL_IMAGE_WIDTH_SMALL);
+ tem_set('wfpl_image_width_thumb', WFPL_IMAGE_WIDTH_THUMB);
tem_set('form', $data);
tem_set('$head'); # wysiwyg init goes in <head>
}
--- /dev/null
+<?php
+
+define('DOCROOT', __DIR__ .'/');
+require_once(DOCROOT . 'config.php');
+require_once(DOCROOT . 'inc/wfpl/upload.php');
+
+function cms_images_autoresize_main_abort_404() {
+ http_response_code('404');
+ header('HTTP/1.0 404 File Not Found');
+ header('Content-Type: text/plain');
+ print('404: File not found');
+ exit();
+}
+
+function cms_images_autoresize_main() {
+ # figure out what file was requested
+ $out_fn = $_SERVER['REDIRECT_URL'];
+ $out_fn = preg_replace('|[?].*|', '', $out_fn); # apache 2.4.17
+ $out_fn = preg_replace('|.*/|', '', $out_fn);
+ $matches = array();
+ if (!preg_match('/^([0-9a-f]+)w([0-9]+)[.](png|jpg)$/', $out_fn, $matches)) {
+ cms_images_autoresize_main_abort_404();
+ }
+
+ $basename = $matches[1];
+ $width = (int)$matches[2];
+ $ext = $matches[3];
+ $in_fn = "$basename.$ext";
+ $in_path = DOCROOT . 'cms_images/' . $in_fn;
+ $out_path = DOCROOT . 'cms_images/' . $out_fn;
+ $lock_path = $out_path . '.lock';
+
+ if (!in_array($width, $GLOBALS['wfpl_image_widths'], true)) {
+ cms_images_autoresize_main_abort_404();
+ }
+
+ if (!file_exists($in_path)) {
+ cms_images_autoresize_main_abort_404();
+ }
+
+ @$lock = fopen($lock_path, 'x');
+ if (!$lock) {
+ # delete lock file if it's stale
+ $s = stat($lock_path);
+ if ($s && $s['mtime'] + 3 < time()) {
+ unlink($lock_path);
+ } else {
+ # if it's fresh, exit with temporary error
+ header('HTTP/1.0 503 Service Unavailable');
+ header('Content-Type: text/plain');
+ header('Retry-After: 4');
+ print("503 Service Unavailable (try again soon)\n");
+ var_dump($s);
+ var_dump(time());
+ exit();
+ }
+ }
+
+ imagemagick_convert($in_path, $out_path,
+ '-geometry '
+ . $width
+ . 'x'
+ . ($width * 2)
+ . "'>'"
+ );
+
+ # done! kill the lock
+ fclose($lock);
+ unlink($lock_path);
+
+ if (!headers_sent()) {
+ header('Content-Type: ' . ($ext = 'jpg' ? 'image/jpeg' : 'image/png'));
+ readfile($out_path);
+ }
+}
+cms_images_autoresize_main();
# CMS login passwords are stored in the database. See admin_users.php
date_default_timezone_set('America/New_York');
+# If you change these, update style.styl too
+define('WFPL_IMAGE_WIDTH_FULL', 900);
+define('WFPL_IMAGE_WIDTH_SMALL', 336); # this is "sidebar_width" in style.styl
+define('WFPL_IMAGE_WIDTH_THUMB', 70);
+$GLOBALS['wfpl_image_widths'] = array(
+ WFPL_IMAGE_WIDTH_FULL,
+ WFPL_IMAGE_WIDTH_SMALL,
+ WFPL_IMAGE_WIDTH_THUMB
+);
+
# Enable features, auto-includes
require_once(DOCROOT . 'inc/wfpl/format.php');
require_once(DOCROOT . 'inc/wfpl/db.php');
-Subproject commit eb268173999615e857af705883ce8c94c5c039dd
+Subproject commit f8a8d44598bdb6e4446920b8d10d1bc62916c9aa
////////////////
// dimensions (max. these will scale down for smaller screens except in ie8)
+// if you change these, update config.php too
site_width = 900px
site_padding = 15px
sidebar_padding = 20px
-// floating images (from pastable example code on admin_images)
+// obsolete floating images (from pastable example code on admin_images)
span.wfpl_ifl
display: block
float: left
& + &
margin-left: 10px
-.wfpl_fr
+.wfpl_li, .wfpl_ci, .wfpl_ri, .wfpl_fi
display: block
+ margin-bottom: 1%
+ clear: both
+ font-size: 80%
+ text-align: right
+ .wfpl_i
+ display: block
+ width: 100%
+ background-size: 100% auto
+ background-repeat: no-repeat
+ background-position: 50% top
+ margin-bottom: 3px // padding above caption
+ // clip line with (which is there so ckeditor doesn't delete this)
+ height: 0
+ overflow: hidden
+.wfpl_li, .wfpl_ci, .wfpl_ri
+ width: sidebar_width // when window is large
+.wfpl_li
+ float: left
+ margin-right: sidebar_padding
+.wfpl_ci
+ margin-left: auto
+ margin-right: auto
+.wfpl_ri
float: right
margin-left: sidebar_padding
- margin-bottom: 1%
- width: sidebar_width // simple when big, and for ie8 (which ignores media queries)
@media screen and (max-width: (content_width / vw_to_content_width))
#centerer
width: auto
margin: 0
padding: unit(site_padding_pct * 100, '%')
- .wfpl_fr
+ .wfpl_li, .wfpl_ri
width: linear_scale_calc(content_width, sidebar_width, sidebar_width, sidebar_width * .5)
+ .wfpl_ri
margin-left: unit(sidebar_padding_pct * 100, '%')
+ .wfpl_li
+ margin-right: unit(sidebar_padding_pct * 100, '%')
@media screen and (max-width: (sidebar_width / vw_to_content_width))
- .wfpl_fr
+ .wfpl_li, .wfpl_ci, .wfpl_ri
float: none
margin-left: 0
- margin-bottom: 0
+ margin-right: 0
width: 100%
-.wfpl_fr > .wfpl_i
- display: block
- width: 100%
- height: auto
+
+// does not contain a .wfpl_i
+.wfpl_thumb
+ display: inline-block
+ width: 70px
+ height: 70px;
background-size: contain
+ background-position: 50% 50%
background-repeat: no-repeat
- background-position: 50% top
- font-size: 80%
- text-align: right
#mobile_menu_button
display: none;