Add diagnostics to check integrity of data folder master
Add diagnostics to check integrity of data folder

<?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 getFirstDate() {
  // not romance help
  $datedFiles = scandir(DATA_DIR); // sorted descendingly by default
  if (sizeof($datedFiles) > 2) {// always at least 2 even for an empty folder because of ./ and ../
  return getDateFromFilename($datedFiles[2]);
  } else {
  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 $textDayName = date("l", $date);
); $sizeDayName = 24 + round(($source_image_height - 1000) / 1000) * 2;
} $fontDayName = "./img/mplus-1p-medium.ttf";
$date = strtotime($displayDate); $bboxDayName = calculateTextBox($textDayName, $fontDayName, $sizeDayName);
// First we create our bounding box for the first text  
$textDayName = date("l",$date); $textDate = date("jS F Y", $date);
$sizeDayName = 18; $sizeDate = 24 + floor(($source_image_height - 1000) / 100);
$fontDayName = "./img/mplus-1p-medium.ttf"; $fontDate = "./img/mplus-1p-regular.ttf";
$bboxDayName = calculateTextBox($textDayName,$fontDayName,$sizeDayName); $bboxDate = calculateTextBox($textDate, $fontDate, $sizeDate);
   
$textDate = date("jS F Y",$date); $margin = 15;
$sizeDate = 14;  
$fontDate = "./img/mplus-1p-regular.ttf"; // Draw a black rectangle
$bboxDate = calculateTextBox($textDate,$fontDate,$sizeDate); imagefilledrectangle($source_gd_image, 0, 0, $source_image_width, $margin * 2 + $bboxDayName['height'], $black);
   
$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 // 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:b/diagnostics.php (new)
  <?php
 
  include "common.inc.php";
  if (!($firstDate = getFirstDate()))
  die("Cannot complete diagnotics, cannot get first file date");
  $currentDate = $firstDate;
  if (!($lastDate = getPreviousDate()))
  die("Cannot complete diagnotics, cannot get last file date");
  $hashes = Array();
  while ($currentDate != $lastDate) {
  $results = glob(DATA_DIR . "/" . $currentDate . "*");
  if (sizeof($results) == 0) {
  echo "Error on $currentDate, no photo found for that date <br>";
  } else if (sizeof($results) > 1) {
  echo "Error on $currentDate, more than one photo found for that date: <br>";
  var_dump($results);
  echo "<br>";
  } else {
  // normal day
  $fname = basename($results[0]);
  $fnParts = explode(".", $fname);
  if (sizeof($fnParts) < 3) {
  echo "Error on $currentDate, malformed file name {$fname} <br>";
  } else {
  if (strtotime($currentDate) != strtotime($fnParts[0])) {
  echo "Error on $currentDate, file name {$fname} date does not match expected date <br>";
  }
  if ($imgsize = getimagesize($results[0])) {
  if ($imgsize[0] < MIN_IMAGE_SIZE || $imgsize[1] < MIN_IMAGE_SIZE || $imgsize[0] != $imgsize[1]) {
  echo "Error on $currentDate, file name {$fname} is not large enough dimensions or non-square dimensions <br>";
  }
  } else {
  echo "Error on $currentDate, file name {$fname} could not be opened as an image file. File may have been corrupted <br>";
  }
  $hash = md5_file($results[0]);
  if ($hash != $fnParts[1]) {
  echo "Error on $currentDate, file name {$fname} hash does not match expected hash. File may have been corrupted or altered <br>";
  }
  if (in_array($hash, array_keys($hashes))) {
  echo "Error on $currentDate, file {$fname} hash matches that of {$hashes[$hash]}. Files may be identitical duplicates of the same image <br>";
  }
  $hashes[$hash] = $fname;
 
  if (sizeof($fnParts[2]) > 3 || ($fnParts[2] != "png" && $fnParts[2] != "jpg")) {
  echo "Error on $currentDate, file name {$fname} extension unexpected <br>";
  }
  }
  }
 
  // go to next day
  $currentDate = date("Y-m-d", strtotime("+1 day", strtotime($currentDate)));
  }
  echo "Scanned files from $firstDate to $currentDate, no errors detected<br>";
  ?>
 
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
This is free and unencumbered software released into the public domain. This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any binary, for any purpose, commercial or non-commercial, and by any
means. means.
In jurisdictions that recognize copyright laws, the author or authors In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit 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 of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this relinquishment in perpetuity of all present and future rights to this
software under copyright law. software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 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 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE. OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org/> For more information, please refer to <http://unlicense.org/>
Major components: Major components:
Modernizr: MIT/BSD license Modernizr: MIT/BSD license
jQuery: MIT/GPL license jQuery: MIT/GPL license
DD_belatedPNG: MIT license DD_belatedPNG: MIT license
YUI Profiling: BSD license YUI Profiling: BSD license
HTML5Doctor CSS reset: Public Domain HTML5Doctor CSS reset: Public Domain
CSS Reset Reloaded: Public Domain CSS Reset Reloaded: Public Domain
PHP Calendar by Keith Devens PHP Calendar by Keith Devens
Open Source License 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. 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 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 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: 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. 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. 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. 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. 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. 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: 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. 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.
   
file:a/upload.php -> file:b/upload.php
<?php <?php
include("common.inc.php"); include("common.inc.php");
include_header("upload"); include_header("upload");
?> ?>
   
<form name="upload" action="confirmUpload.php" method="POST" ENCTYPE="multipart/form-data"> <form name="upload" action="confirmUpload.php" method="POST" ENCTYPE="multipart/form-data">
Select the file to upload: <input type="file" name="userfile"> Select the file to upload: <input type="file" name="userfile" accept="image/*">
<input type="submit" name="upload" value="upload"> <input type="submit" name="upload" value="upload">
</form> </form>
   
<?php <?php
include_footer(); include_footer();
?> ?>