From: Alexander Sadleir Date: Sat, 03 Sep 2011 15:27:26 +0000 Subject: Add image upload and image watermarking X-Git-Url: https://maxious.lambdacomplex.org/git/?p=photocalendar.git&a=commitdiff&h=675ae05becd57b1e12f60e5c0f3486386aa3e54b --- Add image upload and image watermarking --- --- /dev/null +++ b/.htaccess @@ -1,1 +1,504 @@ - +# Apache configuration file +# httpd.apache.org/docs/2.2/mod/quickreference.html + +# Note .htaccess files are an overhead, this logic should be in your Apache config if possible +# httpd.apache.org/docs/2.2/howto/htaccess.html + +# Techniques in here adapted from all over, including: +# Kroc Camen: camendesign.com/.htaccess +# perishablepress.com/press/2006/01/10/stupid-htaccess-tricks/ +# Sample .htaccess file of CMS MODx: modxcms.com + + +### +### If you run a webserver other than apache, consider: +### github.com/paulirish/html5-boilerplate-server-configs +### + + + +# ---------------------------------------------------------------------- +# Better website experience for IE users +# ---------------------------------------------------------------------- + +# Force the latest IE version, in various cases when it may fall back to IE7 mode +# github.com/rails/rails/commit/123eb25#commitcomment-118920 +# Use ChromeFrame if it's installed for a better experience for the poor IE folk + + + Header set X-UA-Compatible "IE=Edge,chrome=1" + # mod_headers can't match by content-type, but we don't want to send this header on *everything*... + + Header unset X-UA-Compatible + + + + +# ---------------------------------------------------------------------- +# Cross-domain AJAX requests +# ---------------------------------------------------------------------- + +# Serve cross-domain ajax requests, disabled. +# enable-cors.org +# code.google.com/p/html5security/wiki/CrossOriginRequestSecurity + +# +# Header set Access-Control-Allow-Origin "*" +# + + + +# ---------------------------------------------------------------------- +# Webfont access +# ---------------------------------------------------------------------- + +# Allow access from all domains for webfonts. +# Alternatively you could only whitelist your +# subdomains like "subdomain.example.com". + + + + Header set Access-Control-Allow-Origin "*" + + + + + +# ---------------------------------------------------------------------- +# Proper MIME type for all files +# ---------------------------------------------------------------------- + + +# JavaScript +# Normalize to standard type (it's sniffed in IE anyways) +# tools.ietf.org/html/rfc4329#section-7.2 +AddType application/javascript js + +# Audio +AddType audio/ogg oga ogg +AddType audio/mp4 m4a + +# Video +AddType video/ogg ogv +AddType video/mp4 mp4 m4v +AddType video/webm webm + +# SVG. +# Required for svg webfonts on iPad +# twitter.com/FontSquirrel/status/14855840545 +AddType image/svg+xml svg svgz +AddEncoding gzip svgz + +# Webfonts +AddType application/vnd.ms-fontobject eot +AddType application/x-font-ttf ttf ttc +AddType font/opentype otf +AddType application/x-font-woff woff + +# Assorted types +AddType image/x-icon ico +AddType image/webp webp +AddType text/cache-manifest appcache manifest +AddType text/x-component htc +AddType application/x-chrome-extension crx +AddType application/x-xpinstall xpi +AddType application/octet-stream safariextz +AddType text/x-vcard vcf + + + +# ---------------------------------------------------------------------- +# Allow concatenation from within specific js and css files +# ---------------------------------------------------------------------- + +# e.g. Inside of script.combined.js you could have +# +# +# and they would be included into this single file. + +# This is not in use in the boilerplate as it stands. You may +# choose to name your files in this way for this advantage or +# concatenate and minify them manually. +# Disabled by default. + +# +# Options +Includes +# AddOutputFilterByType INCLUDES application/javascript application/json +# SetOutputFilter INCLUDES +# +# +# Options +Includes +# AddOutputFilterByType INCLUDES text/css +# SetOutputFilter INCLUDES +# + + +# ---------------------------------------------------------------------- +# Gzip compression +# ---------------------------------------------------------------------- + + + +# Force deflate for mangled headers developer.yahoo.com/blogs/ydn/posts/2010/12/pushing-beyond-gzipping/ + + + SetEnvIfNoCase ^(Accept-EncodXng|X-cept-Encoding|X{15}|~{15}|-{15})$ ^((gzip|deflate)\s*,?\s*)+|[X~-]{4,13}$ HAVE_Accept-Encoding + RequestHeader append Accept-Encoding "gzip,deflate" env=HAVE_Accept-Encoding + + + +# HTML, TXT, CSS, JavaScript, JSON, XML, HTC: + + FilterDeclare COMPRESS + FilterProvider COMPRESS DEFLATE resp=Content-Type $text/html + FilterProvider COMPRESS DEFLATE resp=Content-Type $text/css + FilterProvider COMPRESS DEFLATE resp=Content-Type $text/plain + FilterProvider COMPRESS DEFLATE resp=Content-Type $text/xml + FilterProvider COMPRESS DEFLATE resp=Content-Type $text/x-component + FilterProvider COMPRESS DEFLATE resp=Content-Type $application/javascript + FilterProvider COMPRESS DEFLATE resp=Content-Type $application/json + FilterProvider COMPRESS DEFLATE resp=Content-Type $application/xml + FilterProvider COMPRESS DEFLATE resp=Content-Type $application/xhtml+xml + FilterProvider COMPRESS DEFLATE resp=Content-Type $application/rss+xml + FilterProvider COMPRESS DEFLATE resp=Content-Type $application/atom+xml + FilterProvider COMPRESS DEFLATE resp=Content-Type $application/vnd.ms-fontobject + FilterProvider COMPRESS DEFLATE resp=Content-Type $image/svg+xml + FilterProvider COMPRESS DEFLATE resp=Content-Type $application/x-font-ttf + FilterProvider COMPRESS DEFLATE resp=Content-Type $font/opentype + FilterChain COMPRESS + FilterProtocol COMPRESS DEFLATE change=yes;byteranges=no + + + + # Legacy versions of Apache + AddOutputFilterByType DEFLATE text/html text/plain text/css application/json + AddOutputFilterByType DEFLATE application/javascript + AddOutputFilterByType DEFLATE text/xml application/xml text/x-component + AddOutputFilterByType DEFLATE application/xhtml+xml application/rss+xml application/atom+xml + AddOutputFilterByType DEFLATE image/svg+xml application/vnd.ms-fontobject application/x-font-ttf font/opentype + + + + + +# ---------------------------------------------------------------------- +# Expires headers (for better cache control) +# ---------------------------------------------------------------------- + +# These are pretty far-future expires headers. +# They assume you control versioning with cachebusting query params like +# - - - - - - - - - - + Upload a new day
+ Help/Instructions
+
+ 2) {// always at least 2 even for an empty folder because of ./ and ../ + return removeImageFileExtensions($datedFiles[sizeof($datedFiles)-1]); +} else { + return false; +} +} +function getPhoto($displayDate) { + $cacheFile = CACHE_DIR.$displayDate.".png"; + if (file_exists($cacheFile)) { + return $cacheFile; + } else { + if (file_exists(DATA_DIR.$displayDate.".jpg")) { + $source_gd_image = imagecreatefromjpeg( DATA_DIR.$displayDate.".jpg"); + + } else if (file_exists(DATA_DIR.$displayDate.".png")) { + $source_gd_image = imagecreatefrompng( DATA_DIR.$displayDate.".png" ); + } else { + return false; + } + + if ( $source_gd_image === false ) + { + return false; + } +$source_image_width = imagesx($source_gd_image); + $source_image_height = imagesy($source_gd_image); + + $header_gd_image = imagecreatefrompng( "img/header.png" ); +$header_image_width = imagesx($header_gd_image); + $header_image_height = imagesy($header_gd_image); + + $white = imagecolorallocate($source_gd_image, 255, 255, 255); + $black = imagecolorallocate($source_gd_image, 0, 0, 0); + function calculateTextBox($text,$fontFile,$fontSize) { + /************ + simple function that calculates the *exact* bounding box (single pixel precision). + The function returns an associative array with these keys: + left, top: coordinates you will pass to imagettftext + width, height: dimension of the image you have to create + *************/ + $rect = imagettfbbox($fontSize,0,$fontFile,$text); + $minX = min(array($rect[0],$rect[2],$rect[4],$rect[6])); + $maxX = max(array($rect[0],$rect[2],$rect[4],$rect[6])); + $minY = min(array($rect[1],$rect[3],$rect[5],$rect[7])); + $maxY = max(array($rect[1],$rect[3],$rect[5],$rect[7])); + + return array( + "left" => abs($minX) - 1, + "top" => abs($minY) - 1, + "width" => $maxX - $minX, + "height" => $maxY - $minY, + "box" => $rect + ); +} +$date = strtotime($displayDate); +// First we create our bounding box for the first text +$textDayName = date("l",$date); +$sizeDayName = 18; +$fontDayName = "./img/mplus-1p-medium.ttf"; +$bboxDayName = calculateTextBox($textDayName,$fontDayName,$sizeDayName); + +$textDate = date("jS F Y",$date); +$sizeDate = 14; +$fontDate = "./img/mplus-1p-regular.ttf"; +$bboxDate = calculateTextBox($textDate,$fontDate,$sizeDate); + +$margin = 15; +$maxX = $header_image_width + $margin*2 + max($bboxDayName['width'],$bboxDate['width']) + $margin*2; +$maxY = max($header_image_height + $margin*2 , ($bboxDayName['height']+$margin+$bboxDate['height'])); + +// Draw a white rectangle +imagefilledrectangle($source_gd_image, 0, 0, $maxX, $maxY, $white); + +imagecopy($source_gd_image, $header_gd_image,$margin,$margin,0,0,$header_image_width,$header_image_height); + +// Write it +imagettftext($source_gd_image, $sizeDayName, 0, $header_image_width+$margin*2+$bboxDayName['left'], $margin+$bboxDayName['top'], $black, $fontDayName, $textDayName); +imagettftext($source_gd_image, $sizeDate, 0, $header_image_width+$margin*2+$bboxDate['left'], $margin+$bboxDayName['height']+$margin+$bboxDate['top'], $black, $fontDate, $textDate); + + imagepng( $source_gd_image, $cacheFile, 9 ); + imagedestroy( $source_gd_image ); + return $cacheFile; + } +} +function getCalendarDays($year,$month) { + $result = Array(); + if ($handle = opendir(DATA_DIR)) { + while (false !== ($file = readdir($handle))) { + if ($file != "." && $file != ".." && startsWith($file,"$year-$month")) { + $parts = explode("-",$file); + $day = removeImageFileExtensions($parts[2]); + $result[$day]=Array("index.php?date=$year-$month-$day",'linked-day'); + } + } + } + ksort($result); + return $result; +} +function getCalendarMonths() { + $months = Array(); + if ($handle = opendir(DATA_DIR)) { + while (false !== ($file = readdir($handle))) { + if ($file != "." && $file != "..") { + $parts = explode("-",$file); + $months[$parts[0].$parts[1]]=Array("month"=>$parts[1],"year"=>$parts[0]); + } + } + } + return $months; +} +function startsWith($haystack, $needle) +{ + // source: http://stackoverflow.com/questions/834303/php-startswith-and-endswith-functions + $length = strlen($needle); + return (substr($haystack, 0, $length) === $needle); +} +function removeImageFileExtensions($filename) { + return str_replace(Array(".png",".jpg"),"",$filename); +} ?> --- a/config.inc.php +++ b/config.inc.php @@ -1,1 +1,13 @@ + --- a/confirmUpload.php +++ b/confirmUpload.php @@ -1,1 +1,46 @@ +upload page'; + $error = true; +} else { + $imageinfo = getimagesize($_FILES['userfile']['tmp_name']); + $source_image_type = $imageinfo['mime']; +$source_image_width = $imageinfo[0]; + $source_image_height = $imageinfo[1]; +} + +if($error == false && ($source_image_type != 'image/png' && $source_image_type != 'image/jpeg')) { + echo "Sorry, we only accept PNG and JPEG images. Your image was of type '$source_image_type'.
"; + $error = true; +} +if($error == false && ($source_image_width < MIN_IMAGE_SIZE || $source_image_height < MIN_IMAGE_SIZE)) { + echo "Sorry, we only accept images larger than ".MIN_IMAGE_SIZE." pixels. Your image was $source_image_width x $source_image_height pixels big.
"; + $error = true; +} + +if($error == false && ($source_image_width != $source_image_height)) { + echo "Sorry, we only accept images that are exactly square (the height is the same as the width). Your image was $source_image_width x $source_image_height pixels big.
"; + $error = true; +} +if (!$error) { + $fileExtension = ($source_image_type == 'image/png' ? ".png" : ".jpg"); + $fileDate = getNextAvailableDate(); + echo "Uploaded file meets all necessary requirements, next available date is $fileDate
"; + $uploaddir = '/var/spool/uploads/'; # Outside of web root + $uploadfile = DATA_DIR . $fileDate . $fileExtension; + if (file_exists($uploadfile)) { + echo "Oh no! A file for $fileDate already exists! Please retry in a moment
"; + } else { + if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) { + echo "File was successfully uploaded.\n
"; + } else { + echo "File uploading failed.\n
"; + } + } +} +include_footer(); +?> --- a/css/screen.css +++ /dev/null @@ -1,150 +1,1 @@ -body { - margin:0; - padding:0; - border:0; /* This removes the border around the viewport in old versions of IE */ - width:100%; - background:#fff; - min-width:600px; /* Minimum width of layout - remove line if not required */ - /* The min-width property does not work in old versions of Internet Explorer */ - font-size:90%; -} -a { - color:#369; -} -a:hover { - color:#fff; - background:#369; - text-decoration:none; -} -h1, h2, h3 { - margin:.8em 0 .2em 0; - padding:0; -} -p { - margin:.4em 0 .8em 0; - padding:0; -} -img { - margin:10px 0 5px; -} -#ads img { - display:block; - padding-top:10px; -} -/* Header styles */ -#header { - clear:both; - float:left; - width:100%; -} -#header { - border-bottom:1px solid #000; -} -#header p, -#header h1, -#header h2 { - padding:.4em 15px 0 15px; - margin:0; -} -#header ul { - clear:left; - float:left; - width:100%; - list-style:none; - margin:10px 0 0 0; - padding:0; -} -#header ul li { - display:inline; - list-style:none; - margin:0; - padding:0; -} -#header ul li a { - display:block; - float:left; - margin:0 0 0 1px; - padding:3px 10px; - text-align:center; - background:#eee; - color:#000; - text-decoration:none; - position:relative; - left:15px; - line-height:1.3em; -} -#header ul li a:hover { - background:#369; - color:#fff; -} -#header ul li a.active, -#header ul li a.active:hover { - color:#fff; - background:#000; - font-weight:bold; -} -#header ul li a span { - display:block; -} -/* 'widths' sub menu */ -#layoutdims { - clear:both; - background:#eee; - border-top:4px solid #000; - margin:0; - padding:6px 15px !important; - text-align:right; -} -/* column container */ -.colmask { - position:relative; /* This fixes the IE7 overflow hidden bug */ - clear:both; - float:left; - width:100%; /* width of whole page */ - overflow:hidden; /* This chops off any overhanging divs */ -} -/* common column settings */ -.colright, -.colmid, -.colleft { - float:left; - width:100%; - position:relative; -} -.col1, -.col2, -.col3 { - float:left; - position:relative; - padding:0 0 1em 0; - overflow:hidden; -} -/* 2 Column (right menu) settings */ -.rightmenu { - background:#eee; /* right column background colour */ -} -.rightmenu .colleft { - right:25%; /* right column width */ - background:#fff; /* left column background colour */ -} -.rightmenu .col1 { - width:71%; /* left column content width (left column width minus left and right padding) */ - left:27%; /* (right column width) plus (left column left padding) */ -} -.rightmenu .col2 { - width:21%; /* right column content width (right column width minus left and right padding) */ - left:31%; /* (right column width) plus (left column left and right padding) plus (right column left padding) */ -} -/* Footer styles */ -#footer { - clear:both; - float:left; - width:100%; - border-top:1px solid #000; -} -#footer p { - padding:10px; - margin:0; -} - --- a/css/style.css +++ b/css/style.css @@ -67,70 +67,7 @@ ========================================================================== */ -/* Header styles */ -#header { - clear:both; - float:left; - width:100%; -} -#header { - border-bottom:1px solid #000; -} -#header p, -#header h1, -#header h2 { - padding:.4em 15px 0 15px; - margin:0; -} -#header ul { - clear:left; - float:left; - width:100%; - list-style:none; - margin:10px 0 0 0; - padding:0; -} -#header ul li { - display:inline; - list-style:none; - margin:0; - padding:0; -} -#header ul li a { - display:block; - float:left; - margin:0 0 0 1px; - padding:3px 10px; - text-align:center; - background:#eee; - color:#000; - text-decoration:none; - position:relative; - left:15px; - line-height:1.3em; -} -#header ul li a:hover { - background:#369; - color:#fff; -} -#header ul li a.active, -#header ul li a.active:hover { - color:#fff; - background:#000; - font-weight:bold; -} -#header ul li a span { - display:block; -} -/* 'widths' sub menu */ -#layoutdims { - clear:both; - background:#eee; - border-top:4px solid #000; - margin:0; - padding:6px 15px !important; - text-align:right; -} + /* column container */ .colmask { position:relative; /* This fixes the IE7 overflow hidden bug */ @@ -140,16 +77,13 @@ overflow:hidden; /* This chops off any overhanging divs */ } /* common column settings */ -.colright, -.colmid, .colleft { float:left; width:100%; position:relative; } .col1, -.col2, -.col3 { +.col2 { float:left; position:relative; padding:0 0 1em 0; @@ -157,7 +91,9 @@ } .col2 { text-align: center; - height: 100%; +} +.col2 table { + width: 100%; } /* 2 Column (right menu) settings */ .rightmenu { --- a/help.php +++ b/help.php @@ -1,1 +1,22 @@ - + +
+
+ +
+Rules for uploading: +
    +
  • Must be larger than 1000 pixels
  • +
  • Must be exactly square
  • +
  • Must be in JPG/PNG format (BMP/TIFF is too big, GIF has too little colors)
  • +
+
+ +
+
'; +include_footer(); +?> --- a/humans.txt +++ b/humans.txt @@ -1,12 +1,10 @@ /* the humans responsible & colophon */ /* humanstxt.org */ - /* TEAM */ - : - Site: - Twitter: - Location: + Lead Developer: Alexander Sadleir + Site: http://maxious.lambdacomplex.org + Twitter: @maxious /* THANKS */ Names (& URL): @@ -14,31 +12,4 @@ /* SITE */ Standards: HTML5, CSS3 Components: Modernizr, jQuery - Software: - - - - -o/- - +oo//- - :ooo+//: - -ooooo///- - /oooooo//: - :ooooooo+//- - -+oooooooo///- - -://////////////+oooooooooo++////////////:: - :+ooooooooooooooooooooooooooooooooooooo+:::- - -/+ooooooooooooooooooooooooooooooo+/::////:- - -:+oooooooooooooooooooooooooooo/::///////:- - --/+ooooooooooooooooooooo+::://////:- - -:+ooooooooooooooooo+:://////:-- - /ooooooooooooooooo+//////:- - -ooooooooooooooooooo////- - /ooooooooo+oooooooooo//: - :ooooooo+/::/+oooooooo+//- - -oooooo/::///////+oooooo///- - /ooo+::://////:---:/+oooo//: - -o+/::///////:- -:/+o+//- - :-:///////:- -:/:// - -////:- --//: - -- -: - + Software: HTML5 Boilerplate, PHP Calendar by Keith Devens --- a/index.php +++ b/index.php @@ -1,20 +1,23 @@ -
- -
- jdfgjkdfhjghdfjhgjdfgdf'; - echo '
'; - $days = array( - 2=>array('/weblog/archive/2004/Jan/02','linked-day'), - 3=>array('/weblog/archive/2004/Jan/03','linked-day'), - 8=>array('/weblog/archive/2004/Jan/08','linked-day'), - 22=>array('/weblog/archive/2004/Jan/22','linked-day') - ); - echo generate_calendar(2004, 1, $days, 3); +?> +
+
+ +
+"; +} else { +echo ''; +} +?> +
+
'; --- a/readme.txt +++ b/readme.txt @@ -1,6 +1,86 @@ +Photo Calendar + Minimum Requirements PHP4 with gd2 library enabled -cache should be writable by webserver, not directory listable -data should not be placed anywhere it is accessable from the web, but writable by webserver +Install: +Unzip onto a webserver and you're done! + +Cache should be writable by webserver, in the web accessable directory, not directory listable +Data should not be placed anywhere it is accessable from the web, but should still be writable by webserver + +Note on SELinux systems, http accessable files must be labeled: +chcon -v --type=httpd_sys_content_t photoCalendar +and also read writable folders +chcon -v --type=httpd_sys_script_rw_t photoCalendar/cache + +Bundled Software Licensing/Copyright: + +Calendar icon from http://www.pdclipart.org/thumbnails.php?album=29 under Public Domain licence + +M+ FONTS Copyright (C) 2002-2011 M+ FONTS PROJECT +http://mplus-fonts.sourceforge.jp/mplus-outline-fonts/ + +These fonts are free softwares. +Unlimited permission is granted to use, copy, and distribute it, with +or without modification, either commercially and noncommercially. +THESE FONTS ARE PROVIDED "AS IS" WITHOUT WARRANTY. + + +HTML5 Boilerplate + +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to + +Major components: + +Modernizr: MIT/BSD license +jQuery: MIT/GPL license +DD_belatedPNG: MIT license +YUI Profiling: BSD license +HTML5Doctor CSS reset: Public Domain +CSS Reset Reloaded: Public Domain + + +PHP Calendar by Keith Devens +Open Source License +This license applies to all original software available from keithdevens.com unless the software is marked otherwise. This license is most like the Artistic License. I wrote this license separately and then discovered that the Artistic license has a similar philosophy. + +The code you have is Open Source. You have permission to use or modify the code for your own purposes: commercial, private, or educational. However, the author (me) retains ownership (copyright) over the code - it is not public domain. + +The unmodified source may be redistributed with no restrictions, provided that all files in the original distribution are included and unchanged. + +The modified source may be redistributed under the following conditions: + +Changes to the source must be made available and placed in the public domain or released on the same terms as this license. +You must clearly state in each modified file what you have changed. This does not preclude a separate "changes" file from being distributed with the source in addition to the comments you make in the source file. So if you want to give just a short description in the source file, and then supply the location of the changes file containing more detail about the changes, you may do that. +The initial comment header, containing my name, the URL to the homepage for the code, and any other information, must be left intact. You may add other comments below it, of course. +You may use or redistribute this code within a larger product with no restrictions except those that apply to the source when distributed separately. + +Finally, I would appreciate it if you would let me know about any changes you make that you think would be generally useful so I can merge them in with the main source for the benefit of others. + +This shouldn't be necessary, but just in case: +Disclaimer: All code is "use at your own risk". I provide no warranties or guarantees of anything. Though, feel free to e-mail me if you could use some support. --- a/upload.php +++ b/upload.php @@ -1,1 +1,13 @@ + +
+Select the file to upload: + +
+ +