Change to simple white on black autoscaling header
Change to simple white on black autoscaling header

<?php <?php
include_once("config.inc.php"); include_once("config.inc.php");
include("php-calendar.lib.php"); include("php-calendar.lib.php");
   
function include_header($title) { function include_header($title) {
?> ?>
<!doctype html> <!doctype html>
<!--[if lt IE 7]> <html class="no-js ie6 oldie" lang="en"> <![endif]--> <!--[if lt IE 7]> <html class="no-js ie6 oldie" lang="en"> <![endif]-->
<!--[if IE 7]> <html class="no-js ie7 oldie" lang="en"> <![endif]--> <!--[if IE 7]> <html class="no-js ie7 oldie" lang="en"> <![endif]-->
<!--[if IE 8]> <html class="no-js ie8 oldie" lang="en"> <![endif]--> <!--[if IE 8]> <html class="no-js ie8 oldie" lang="en"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en"> <!--<![endif]--> <!--[if gt IE 8]><!--> <html class="no-js" lang="en"> <!--<![endif]-->
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
   
<title></title> <title></title>
<meta name="description" content=""> <meta name="description" content="">
<meta name="author" content=""> <meta name="author" content="">
   
<meta name="viewport" content="width=device-width,initial-scale=1"> <meta name="viewport" content="width=device-width,initial-scale=1">
   
<!-- CSS concatenated and minified via ant build script--> <!-- CSS concatenated and minified via ant build script-->
<link rel="stylesheet" href="css/style.css"> <link rel="stylesheet" href="css/style.css">
<!-- end CSS--> <!-- end CSS-->
   
<script src="js/libs/modernizr-2.0.6.min.js"></script> <script src="js/libs/modernizr-2.0.6.min.js"></script>
</head> </head>
   
<body> <body>
   
<div id="container"> <div id="container">
<header> <header>
   
</header> </header>
<div id="main" role="main"> <div id="main" role="main">
<?php <?php
} }
function include_footer() {  
?> function include_footer() {
</div> ?>
<footer> </div>
  <footer>
</footer>  
</div> <!--! end of #container --> </footer>
<!-- Grab Google CDN's jQuery, with a protocol relative URL; fall back to local if necessary --> </div> <!--! end of #container -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.js"></script> <!-- Grab Google CDN's jQuery, with a protocol relative URL; fall back to local if necessary -->
<script>window.jQuery || document.write('<script src="js/libs/jquery-1.5.1.min.js">\x3C/script>')</script> <script src="//ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.js"></script>
<script type="text/javascript" src="js/jquery.imagefit.js"></script> <script>window.jQuery || document.write('<script src="js/libs/jquery-1.5.1.min.js">\x3C/script>')</script>
<script> <script type="text/javascript" src="js/jquery.imagefit.js"></script>
$(window).load(function(){ <script>
$('.col1').imagefit(); $(window).load(function(){
}); $('.col1').imagefit();
</script> });
</body> </script>
</html> </body>
<?php </html>
  <?php
} }
function include_sidebar() { function include_sidebar() {
?> ?>
<a href="upload.php">Upload a new day</a><br> <a href="upload.php">Upload a new day</a><br>
<a href="help.php">Help/Instructions</a><br> <a href="help.php">Help/Instructions</a><br>
<hr> <hr>
<?php <?php
foreach (getCalendarMonths() as $month) { foreach (getCalendarMonths() as $month) {
echo generate_calendar($month['year'], $month['month'], getCalendarDays($month['year'], $month['month']), 3); echo generate_calendar($month['year'], $month['month'], getCalendarDays($month['year'], $month['month']), 3);
} }
} }
function getNextAvailableDate() { function getNextAvailableDate() {
if ($previousDate = getPreviousDate()) { if ($previousDate = getPreviousDate()) {
$nextDayTime = strtotime("+1 day",strtotime($previousDate)); $nextDayTime = strtotime("+1 day", strtotime($previousDate));
if (date("m",$nextDayTime) == "08" and date("d",$nextDayTime) == "24") { if (date("m", $nextDayTime) == "08" and date("d", $nextDayTime) == "24") {
// skip the 24th of August // skip the 24th of August
$nextDayTime = strtotime("+1 day",$nextDayTime); $nextDayTime = strtotime("+1 day", $nextDayTime);
} }
return date("Y-m-d",$nextDayTime); return date("Y-m-d", $nextDayTime);
} else { } else {
return START_DATE; return START_DATE;
} }
} }
   
  function getDateFromFilename($filename) {
  $fnameParts = explode(".", $filename);
  return $fnameParts[0];
  }
   
  function getFilenameForDate($date, $fileext = "") {
  $results = glob(DATA_DIR . "/" . $date . "*" . $fileext);
  if (sizeof($results) > 0) {
  return $results[0];
  } else
  return false;
  }
   
function getPreviousDate() { function getPreviousDate() {
$datedFiles = scandir(DATA_DIR); // sorted descendingly by default $datedFiles = scandir(DATA_DIR); // sorted descendingly by default
if (sizeof($datedFiles) > 2) {// always at least 2 even for an empty folder because of ./ and ../ if (sizeof($datedFiles) > 2) {// always at least 2 even for an empty folder because of ./ and ../
return removeImageFileExtensions($datedFiles[sizeof($datedFiles)-1]); return getDateFromFilename($datedFiles[sizeof($datedFiles) - 1]);
} else { } else {
return false; return false;
} }
} }
   
function getPhoto($displayDate) { function getPhoto($displayDate) {
$cacheFile = CACHE_DIR.$displayDate.".png"; $cacheFile = CACHE_DIR . $displayDate . ".png";
if (file_exists($cacheFile)) { if (file_exists($cacheFile)) {
return $cacheFile; return $cacheFile;
} else { } else {
if (file_exists(DATA_DIR.$displayDate.".jpg")) { if ($fname = getFilenameForDate($displayDate, ".jpg")) {
$source_gd_image = imagecreatefromjpeg( DATA_DIR.$displayDate.".jpg"); $source_gd_image = imagecreatefromjpeg($fname);
  } else if ($fname = getFilenameForDate($displayDate, ".png")) {
} else if (file_exists(DATA_DIR.$displayDate.".png")) { $source_gd_image = imagecreatefrompng($fname);
$source_gd_image = imagecreatefrompng( DATA_DIR.$displayDate.".png" ); } else {
} else { return false;
return false; }
}  
  if ($source_gd_image === false) {
if ( $source_gd_image === false ) return false;
{ }
return false; $source_image_width = imagesx($source_gd_image);
} $source_image_height = imagesy($source_gd_image);
$source_image_width = imagesx($source_gd_image);  
$source_image_height = imagesy($source_gd_image); $white = imagecolorallocate($source_gd_image, 255, 255, 255);
  $black = imagecolorallocate($source_gd_image, 0, 0, 0);
$header_gd_image = imagecreatefrompng( "img/header.png" );  
$header_image_width = imagesx($header_gd_image); function calculateTextBox($text, $fontFile, $fontSize) {
$header_image_height = imagesy($header_gd_image); /* * **********
  simple function that calculates the *exact* bounding box (single pixel precision).
$white = imagecolorallocate($source_gd_image, 255, 255, 255); The function returns an associative array with these keys:
$black = imagecolorallocate($source_gd_image, 0, 0, 0); left, top: coordinates you will pass to imagettftext
function calculateTextBox($text,$fontFile,$fontSize) { width, height: dimension of the image you have to create
/************ * *********** */
simple function that calculates the *exact* bounding box (single pixel precision). $rect = imagettfbbox($fontSize, 0, $fontFile, $text);
The function returns an associative array with these keys: $minX = min(array($rect[0], $rect[2], $rect[4], $rect[6]));
left, top: coordinates you will pass to imagettftext $maxX = max(array($rect[0], $rect[2], $rect[4], $rect[6]));
width, height: dimension of the image you have to create $minY = min(array($rect[1], $rect[3], $rect[5], $rect[7]));
*************/ $maxY = max(array($rect[1], $rect[3], $rect[5], $rect[7]));
$rect = imagettfbbox($fontSize,0,$fontFile,$text);  
$minX = min(array($rect[0],$rect[2],$rect[4],$rect[6])); return array(
$maxX = max(array($rect[0],$rect[2],$rect[4],$rect[6])); "left" => abs($minX) - 1,
$minY = min(array($rect[1],$rect[3],$rect[5],$rect[7])); "top" => abs($minY) - 1,
$maxY = max(array($rect[1],$rect[3],$rect[5],$rect[7])); "width" => $maxX - $minX,
  "height" => $maxY - $minY,
return array( "box" => $rect
"left" => abs($minX) - 1, );
"top" => abs($minY) - 1, }
"width" => $maxX - $minX,  
"height" => $maxY - $minY, $date = strtotime($displayDate);
"box" => $rect  
);  
}  
$date = strtotime($displayDate);  
// First we create our bounding box for the first text // First we create our bounding box for the first text
$textDayName = date("l",$date); $textDayName = date("l", $date);
$sizeDayName = 18; $sizeDayName = 24 + round(($source_image_height - 1000) / 1000) * 2;
$fontDayName = "./img/mplus-1p-medium.ttf"; $fontDayName = "./img/mplus-1p-medium.ttf";
$bboxDayName = calculateTextBox($textDayName,$fontDayName,$sizeDayName); $bboxDayName = calculateTextBox($textDayName, $fontDayName, $sizeDayName);
   
$textDate = date("jS F Y",$date); $textDate = date("jS F Y", $date);
$sizeDate = 14; $sizeDate = 24 + floor(($source_image_height - 1000) / 100);
$fontDate = "./img/mplus-1p-regular.ttf"; $fontDate = "./img/mplus-1p-regular.ttf";
$bboxDate = calculateTextBox($textDate,$fontDate,$sizeDate); $bboxDate = calculateTextBox($textDate, $fontDate, $sizeDate);
   
$margin = 15; $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 black rectangle
  imagefilledrectangle($source_gd_image, 0, 0, $source_image_width, $margin * 2 + $bboxDayName['height'], $black);
// 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 // 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, $sizeDayName, 0, $margin + $bboxDayName['left'], $margin + $bboxDayName['top'], $white, $fontDayName, $textDayName);
imagettftext($source_gd_image, $sizeDate, 0, $header_image_width+$margin*2+$bboxDate['left'], $margin+$bboxDayName['height']+$margin+$bboxDate['top'], $black, $fontDate, $textDate); imagettftext($source_gd_image, $sizeDate, 0, (($source_image_width - $bboxDayName['width']) / 2) + $bboxDayName['width'] - $bboxDate['left'], + $margin + $bboxDate['top'], $white, $fontDate, $textDate);
   
imagepng( $source_gd_image, $cacheFile, 9 ); imagepng($source_gd_image, $cacheFile, 9);
imagedestroy( $source_gd_image ); imagedestroy($source_gd_image);
return $cacheFile; return $cacheFile;
} }
} }
function getCalendarDays($year,$month) {  
$result = Array(); function getCalendarDays($year, $month) {
if ($handle = opendir(DATA_DIR)) { $result = Array();
while (false !== ($file = readdir($handle))) { if ($handle = opendir(DATA_DIR)) {
if ($file != "." && $file != ".." && startsWith($file,"$year-$month")) { while (false !== ($file = readdir($handle))) {
$parts = explode("-",$file); if ($file != "." && $file != ".." && startsWith($file, "$year-$month")) {
$day = removeImageFileExtensions($parts[2]); $parts = explode("-", $file);
$result[$day]=Array("index.php?date=$year-$month-$day",'linked-day'); $day = getDateFromFilename($parts[2]);
} $result[$day] = Array("index.php?date=$year-$month-$day", 'linked-day');
} }
} }
ksort($result); }
return $result; ksort($result);
} return $result;
  }
   
function getCalendarMonths() { function getCalendarMonths() {
$months = Array(); $months = Array();
if ($handle = opendir(DATA_DIR)) { if ($handle = opendir(DATA_DIR)) {
while (false !== ($file = readdir($handle))) { while (false !== ($file = readdir($handle))) {
if ($file != "." && $file != "..") { if ($file != "." && $file != "..") {
$parts = explode("-",$file); $parts = explode("-", $file);
$months[$parts[0].$parts[1]]=Array("month"=>$parts[1],"year"=>$parts[0]); $months[$parts[0] . $parts[1]] = Array("month" => $parts[1], "year" => $parts[0]);
} }
} }
} }
return $months; return $months;
} }
function startsWith($haystack, $needle)  
{ function startsWith($haystack, $needle) {
// source: http://stackoverflow.com/questions/834303/php-startswith-and-endswith-functions // source: http://stackoverflow.com/questions/834303/php-startswith-and-endswith-functions
$length = strlen($needle); $length = strlen($needle);
return (substr($haystack, 0, $length) === $needle); return (substr($haystack, 0, $length) === $needle);
} }
function removeImageFileExtensions($filename) {  
return str_replace(Array(".png",".jpg"),"",$filename);  
}  
?> ?>
<?php <?php
   
include("common.inc.php"); include("common.inc.php");
include_header("confirmUpload"); include_header("confirmUpload");
$error = false; $error = false;
   
if (!isset($_FILES['userfile'])) { if (!isset($_FILES['userfile'])) {
echo 'No file was uploaded. You should start from the <a href="upload.php">upload page</a>'; echo 'No file was uploaded. You should start from the <a href="upload.php">upload page</a>';
$error = true; $error = true;
} else { } else {
$imageinfo = getimagesize($_FILES['userfile']['tmp_name']); $imageinfo = getimagesize($_FILES['userfile']['tmp_name']);
$source_image_type = $imageinfo['mime']; $source_image_type = $imageinfo['mime'];
$source_image_width = $imageinfo[0]; $source_image_width = $imageinfo[0];
$source_image_height = $imageinfo[1]; $source_image_height = $imageinfo[1];
} }
   
if($error == false && ($source_image_type != 'image/png' && $source_image_type != 'image/jpeg')) { 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'.<br>"; echo "Sorry, we only accept PNG and JPEG images. Your image was of type '$source_image_type'.<br>";
$error = true; $error = true;
} }
if($error == false && ($source_image_width < MIN_IMAGE_SIZE || $source_image_height < MIN_IMAGE_SIZE)) { if ($error == false && ($source_image_width < MIN_IMAGE_SIZE || $source_image_height < MIN_IMAGE_SIZE || $source_image_width != $source_image_height)) {
echo "Sorry, we only accept images larger than ".MIN_IMAGE_SIZE." pixels. Your image was $source_image_width x $source_image_height pixels big. <br>"; echo "Sorry, your image wasn't big enough. In order to ensure that John's calendar looks super-beautiful, we only accept images that are 1000 px or larger and are squares. Your image was $source_image_width x $source_image_height pixels big. <br>";
$error = true; $error = true;
} }
  $hash = md5_file($_FILES['userfile']['tmp_name']);
if($error == false && ($source_image_width != $source_image_height)) { if ($error == false && sizeof(glob(DATA_DIR."*".$hash."*")) > 0) {
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. <br>"; echo "Sorry, we already have an image identical to this one.<br>";
$error = true; $error = true;
} }
   
if (!$error) { if (!$error) {
$fileExtension = ($source_image_type == 'image/png' ? ".png" : ".jpg"); $fileExtension = ($source_image_type == 'image/png' ? ".png" : ".jpg");
$fileDate = getNextAvailableDate(); $fileDate = getNextAvailableDate();
echo "Uploaded file meets all necessary requirements, next available date is $fileDate <br>"; //echo "Uploaded file meets all necessary requirements, next available date is $fileDate <br>";
$uploaddir = '/var/spool/uploads/'; # Outside of web root $uploadfile = DATA_DIR . $fileDate . ".".$hash. $fileExtension;
$uploadfile = DATA_DIR . $fileDate . $fileExtension; if (file_exists($uploadfile)) {
if (file_exists($uploadfile)) { echo "Oh no! A file for $fileDate already exists! Please retry in a moment<br>";
echo "Oh no! A file for $fileDate already exists! Please retry in a moment<br>"; } else {
} else { if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) {
if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) { echo "Yay! Your image has been added as $fileDate. Click <A href='index.php'>here</a> to go back to the site.\n<br>";
echo "File was successfully uploaded.\n<br>"; } else {
} else { echo "File uploading failed.\n<br>";
echo "File uploading failed.\n<br>"; }
} }
}  
} }
include_footer(); include_footer();
?> ?>
file:a/readme.txt -> file:b/readme.txt
Photo Calendar Photo Calendar
Minimum Requirements Minimum Requirements
PHP4 with gd2 library enabled PHP4 with gd2 library enabled
  If it's not installed or not enabled, you will get a "Fatal error: Call to undefined function imagecreatefromjpeg() in common.inc.php on line 88" error when viewing images
Install: Install:
Unzip onto a webserver and you're done! Unzip onto a webserver and you're done!
Cache should be writable by webserver, in the web accessable directory, not directory listable 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 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: Note on SELinux systems, http accessable files must be labeled:
chcon -v --type=httpd_sys_content_t photoCalendar chcon -v --type=httpd_sys_content_t photoCalendar
and also read writable folders and also read writable folders
chcon -v --type=httpd_sys_script_rw_t photoCalendar/cache chcon -v --type=httpd_sys_script_rw_t photoCalendar/cache
Bundled Software Licensing/Copyright: Bundled Software Licensing/Copyright:
Calendar icon from http://www.pdclipart.org/thumbnails.php?album=29 under Public Domain licence Calendar icon from http://www.pdclipart.org/thumbnails.php?album=29 under Public Domain licence
M+ FONTS Copyright (C) 2002-2011 M+ FONTS PROJECT M+ FONTS Copyright (C) 2002-2011 M+ FONTS PROJECT
http://mplus-fonts.sourceforge.jp/mplus-outline-fonts/ http://mplus-fonts.sourceforge.jp/mplus-outline-fonts/
These fonts are free softwares. These fonts are free softwares.
Unlimited permission is granted to use, copy, and distribute it, with Unlimited permission is granted to use, copy, and distribute it, with
or without modification, either commercially and noncommercially. or without modification, either commercially and noncommercially.
THESE FONTS ARE PROVIDED "AS IS" WITHOUT WARRANTY. THESE FONTS ARE PROVIDED "AS IS" WITHOUT WARRANTY.
HTML5 Boilerplate HTML5 Boilerplate