550 lines
15 KiB
PHP
550 lines
15 KiB
PHP
<?php
|
|
// File name: pic.inc.php
|
|
// Description: PHP subroutines to manuplate pictures
|
|
// Date: 2002-04-16
|
|
// Author: imacat <imacat@pristine.com.tw>
|
|
// Copyright: Copyright (C) 2002-2009 Pristine Communications
|
|
|
|
// Set the include path
|
|
if (!defined("INCPATH_SET")) {
|
|
require_once dirname(__FILE__) . "/incpath.inc.php";
|
|
}
|
|
// Referenced subroutines
|
|
require_once "monica/chkfunc.inc.php";
|
|
require_once "monica/gettext.inc.php";
|
|
require_once "monica/htmlchar.inc.php";
|
|
require_once "monica/newsn.inc.php";
|
|
require_once "monica/requri.inc.php";
|
|
require_once "monica/scptpriv.inc.php";
|
|
require_once "monica/xfileio.inc.php";
|
|
|
|
// Settings
|
|
if (!defined("PIC_MAX_WIDTH")) {
|
|
define("PIC_MAX_WIDTH", 800);
|
|
}
|
|
if (!defined("PIC_MAX_HEIGHT")) {
|
|
define("PIC_MAX_HEIGHT", 1024);
|
|
}
|
|
if (!defined("PIC_MAX_RATIO")) {
|
|
define("PIC_MAX_RATIO", 9.99);
|
|
}
|
|
$PIC_VALID_TYPES = array("image/png", "image/jpeg", "image/gif");
|
|
$PIC_VALID_SUFS = array("png", "jpg", "gif");
|
|
$PIC_TYPESUF_MAP = array(
|
|
"image/png" => "png",
|
|
"image/jpeg" => "jpg",
|
|
"image/gif" => "gif");
|
|
$PIC_VALID_POS = array("L", "R");
|
|
$PIC_POS_LABEL = array(
|
|
"L" => N_("Left-aligned"),
|
|
"R" => N_("Right-aligned"));
|
|
$PIC_POS_CSS = array(
|
|
"L" => "float: left;",
|
|
"R" => "float: right;");
|
|
if (!defined("PIC_POS_DEFAULT")) {
|
|
define("PIC_POS_DEFAULT", "L");
|
|
}
|
|
if (!defined("SHOWPIC_SCRIPT")) {
|
|
define("SHOWPIC_SCRIPT", "/admin/showpic.php");
|
|
}
|
|
if (!defined("SHOWPIC_PUBLIC_SCRIPT")) {
|
|
define("SHOWPIC_PUBLIC_SCRIPT", "/showpic.php");
|
|
}
|
|
|
|
// suspend_pic: Suspend a picture to $_SESSION
|
|
function suspend_pic(&$pic)
|
|
{
|
|
$PICS =& pic_deposit();
|
|
// Generate a new random picture ID
|
|
$picid = new_sn_assoc($PICS);
|
|
$pic["sn"] = $picid;
|
|
// Save the current picture
|
|
$PICS[$picid] =& $pic;
|
|
// Return the picture ID
|
|
return $picid;
|
|
}
|
|
|
|
// check_picfile: Check the uploaded picture file
|
|
function check_picfile($column = "picfile")
|
|
{
|
|
$picfile =& $_FILES[$column];
|
|
// Check the file upload status
|
|
switch ($picfile["error"]) {
|
|
case UPLOAD_ERR_INI_SIZE:
|
|
return array("msg"=>NC_("This picture file is too large (Max %s)."),
|
|
"margs"=>array(get_cfg_var("upload_max_filesize")));
|
|
case UPLOAD_ERR_FORM_SIZE:
|
|
return array("msg"=>NC_("This picture file is too large (Max %s)."),
|
|
"margs"=>array(UPLOAD_ERR_FORM_SIZE));
|
|
case UPLOAD_ERR_PARTIAL:
|
|
return array("msg"=>NC_("Upload not completed. Disk may be full or connection may be closed in the half. You may try to upload again, or contact the system administrator for this problem."));
|
|
case UPLOAD_ERR_NO_FILE:
|
|
return array("msg"=>NC_("Please upload the picture."));
|
|
default:
|
|
return array("msg"=>NC_("Upload failed with an unknown error (%d)."),
|
|
"margs"=>array($picfile["error"]));
|
|
case UPLOAD_ERR_OK:
|
|
}
|
|
|
|
// Check the file type
|
|
$picfile["type"] = check_mime_type($picfile["tmp_name"]);
|
|
if (!in_array($picfile["type"], $GLOBALS["PIC_VALID_TYPES"])) {
|
|
return array("msg"=>NC_("Please upload only PNG, JPEG or GIF files."));
|
|
}
|
|
// OK
|
|
return null;
|
|
}
|
|
|
|
// picurl: Get the picture display URL
|
|
function picurl(&$pic, $ratio = null)
|
|
{
|
|
// Default ratio to the picture ratio
|
|
if (is_null($ratio)) {
|
|
// Set the default picture ratio to 1
|
|
if (!array_key_exists("ratio", $pic)) {
|
|
$pic["ration"] = 1;
|
|
}
|
|
$ratio = $pic["ratio"];
|
|
}
|
|
$ratio = sprintf("%0.13F", $ratio);
|
|
$ratio = preg_replace("/(\.[0-9]*?)0+$/", "$1", $ratio);
|
|
$ratio = preg_replace("/\.$/", "", $ratio);
|
|
$showpic = is_admin_script()? SHOWPIC_SCRIPT: SHOWPIC_PUBLIC_SCRIPT;
|
|
// Compose the fields list
|
|
$cols = array();
|
|
// Add the columns
|
|
$cols[] = "sn=" . urlencode($pic["sn"]);
|
|
$cols[] = "ratio=" . urlencode($ratio);
|
|
return $showpic . "?" . implode("&", $cols);
|
|
}
|
|
|
|
// pictype_from_content: Get the picture type from its octet content
|
|
// Refer to the mime.magic file
|
|
function pictype_from_content(&$content)
|
|
{
|
|
// PNG
|
|
if (substr($content, 0, 4) == "\x89PNG") {
|
|
return "image/png";
|
|
}
|
|
// JPEG
|
|
if (substr($content, 0, 2) == "\xFF\xD8") {
|
|
return "image/jpeg";
|
|
}
|
|
// GIF
|
|
if (substr($content, 0, 4) == "GIF8") {
|
|
return "image/gif";
|
|
}
|
|
// No other formats are supported now
|
|
return null;
|
|
}
|
|
|
|
// picinfo: Return the picture infomation
|
|
function picinfo(&$pic, $ratio = 1)
|
|
{
|
|
// Original size not recorded yet
|
|
if ( !array_key_exists("width", $pic)
|
|
|| !array_key_exists("height", $pic)) {
|
|
$img = imagecreatefromstring($pic["content"]);
|
|
$pic["width"] = imagesx($img);
|
|
$pic["height"] = imagesy($img);
|
|
}
|
|
$x = newpicx($pic, $ratio);
|
|
$y = newpicy($pic, $ratio);
|
|
return sprintf(C_("Width: %d, height: %d, ratio: %0.2f"), $x, $y, $ratio);
|
|
}
|
|
|
|
// picstyle: Return the picture style
|
|
function picstyle(&$pic, $ratio = 1)
|
|
{
|
|
// Original size not recorded yet
|
|
if ( !array_key_exists("width", $pic)
|
|
|| !array_key_exists("height", $pic)) {
|
|
$img = imagecreatefromstring($pic["content"]);
|
|
$pic["width"] = imagesx($img);
|
|
$pic["height"] = imagesy($img);
|
|
}
|
|
$x = newpicx($pic, $ratio);
|
|
$y = newpicy($pic, $ratio);
|
|
return sprintf("height: %dpx; width: %dpx;", $y, $x);
|
|
}
|
|
|
|
// check_pic_ratio: Check the sanity of the picture ratio
|
|
function check_pic_ratio(&$pic, &$ratio)
|
|
{
|
|
// Check if the resize ratio is valid
|
|
if (!is_numeric($ratio)) {
|
|
return array("msg"=>NC_("Please specify a numeric ratio."));
|
|
}
|
|
settype($ratio, "float");
|
|
if ($ratio <= 0) {
|
|
return array("msg"=>NC_("Please specify a positive ratio."));
|
|
}
|
|
if ($ratio > PIC_MAX_RATIO) {
|
|
return array("msg"=>NC_("Please specify a ratio less than or equal to %0.2f."),
|
|
"margs"=>array(PIC_MAX_RATIO));
|
|
}
|
|
// The resulted picture is over the limit
|
|
if ( newpicx($pic, $ratio) > PIC_MAX_WIDTH
|
|
|| newpicy($pic, $ratio) > PIC_MAX_HEIGHT) {
|
|
return array("msg"=>NC_("This image is too large to display."));
|
|
}
|
|
// OK
|
|
return null;
|
|
}
|
|
|
|
// best_pic_ratio: Get the best ratio of a picture
|
|
function best_pic_ratio(&$pic)
|
|
{
|
|
// Cache the result
|
|
static $cache;
|
|
// Return the cache
|
|
if (isset($cache)) {
|
|
return $cache;
|
|
}
|
|
|
|
// Original size not recorded yet
|
|
if ( !array_key_exists("width", $pic)
|
|
|| !array_key_exists("height", $pic)) {
|
|
$img = imagecreatefromstring($pic["content"]);
|
|
$pic["width"] = imagesx($img);
|
|
$pic["height"] = imagesy($img);
|
|
}
|
|
// Good
|
|
if ( PIC_MAX_RATIO >= 1
|
|
&& $pic["width"] <= PIC_MAX_WIDTH
|
|
&& $pic["height"] <= PIC_MAX_HEIGHT) {
|
|
$cache = 1;
|
|
return $cache;
|
|
}
|
|
// Too large
|
|
// Find the largest proper ratio
|
|
$rx = floor(PIC_MAX_WIDTH*100 / $pic["width"])/100;
|
|
$ry = floor(PIC_MAX_HEIGHT*100 / $pic["height"])/100;
|
|
// Use the smallest among them
|
|
$cache = min($rx, $ry, PIC_MAX_RATIO);
|
|
return $cache;
|
|
}
|
|
|
|
// newpicx: Calculate the new picture x
|
|
function newpicx(&$pic, $ratio = 1)
|
|
{
|
|
// Original size not recorded yet
|
|
if (!array_key_exists("width", $pic)) {
|
|
$img = imagecreatefromstring($pic["content"]);
|
|
$pic["width"] = imagesx($img);
|
|
}
|
|
// No calculation needed
|
|
if ($ratio == 1) {
|
|
return $pic["width"];
|
|
}
|
|
$x = round($pic["width"] * $ratio);
|
|
// Smallest 1
|
|
if ($x == 0) {
|
|
$x = 1;
|
|
}
|
|
return $x;
|
|
}
|
|
|
|
// newpicy: Calculate the new picture y
|
|
function newpicy(&$pic, $ratio = 1)
|
|
{
|
|
// Original size not recorded yet
|
|
if (!array_key_exists("height", $pic)) {
|
|
$img = imagecreatefromstring($pic["content"]);
|
|
$pic["height"] = imagesy($img);
|
|
}
|
|
// No calculation needed
|
|
if ($ratio == 1) {
|
|
return $pic["height"];
|
|
}
|
|
$y = round($pic["height"] * $ratio);
|
|
// Smallest 1
|
|
if ($y == 0) {
|
|
$y = 1;
|
|
}
|
|
return $y;
|
|
}
|
|
|
|
// pic_exists: Check if a picture exists
|
|
function pic_exists($sn)
|
|
{
|
|
// Check the validity of the serial number first
|
|
if (!check_sn($sn)) {
|
|
return false;
|
|
}
|
|
if (!array_key_exists($sn, pic_deposit())) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// echopic: Output a picture
|
|
function echopic(&$pic, $alt, $ratio = null)
|
|
{
|
|
if (is_null($ratio)) {
|
|
$ratio = best_pic_ratio($pic);
|
|
} else {
|
|
$error = check_pic_ratio($pic, $ratio);
|
|
if (!is_null($error)) {
|
|
$ratio = best_pic_ratio($pic);
|
|
}
|
|
}
|
|
$style = picstyle($pic, $ratio);
|
|
$picinfo = picinfo($pic, $ratio);
|
|
?><img src="<?php echo h(picurl($pic, $ratio)); ?>"
|
|
style="<?php echo h($style); ?>"
|
|
alt="<?php echo h($alt); ?>" />
|
|
<p class="picinfo"><?php echo h($picinfo); ?></p>
|
|
<?php
|
|
return;
|
|
}
|
|
|
|
// echopic_thumbnail: Output an picture thumbnail
|
|
function echopic_thumbnail(&$pic, $alt)
|
|
{
|
|
$url = picurl($pic, $pic["ratio"]);
|
|
$style = picstyle($pic, $pic["ratio"]);
|
|
?><img src="<?php echo h($url); ?>"
|
|
style="<?php echo h($style); ?>"
|
|
alt="<?php echo h($alt); ?>" /><?php
|
|
return;
|
|
}
|
|
|
|
// picpos_label: Output the label of a picture position
|
|
function picpos_label($pos)
|
|
{
|
|
global $PIC_POS_LABEL;
|
|
return C_($PIC_POS_LABEL[$pos]);
|
|
}
|
|
|
|
// resize_pic: Resize a picture
|
|
function &resize_pic(&$pic, $ratio)
|
|
{
|
|
// No need to resize it
|
|
if ($ratio == 1) {
|
|
return $pic;
|
|
}
|
|
$PICS =& pic_deposit();
|
|
|
|
// Initialize the cache base
|
|
if (!array_key_exists("resized", $pic)) {
|
|
$pic["resized"] = array();
|
|
}
|
|
// Return the cache
|
|
$ratio_s = number_format($ratio, 2);
|
|
if (array_key_exists($ratio_s, $pic["resized"])) {
|
|
return $PICS[$pic["resized"][$ratio_s]];
|
|
}
|
|
|
|
// Resize the picture
|
|
$x = $pic["width"];
|
|
$y = $pic["height"];
|
|
$type = $pic["type"];
|
|
$x1 = newpicx($pic, $ratio);
|
|
$y1 = newpicy($pic, $ratio);
|
|
|
|
// Resize it
|
|
$img = imagecreatefromstring($pic["content"]);
|
|
if (imageistruecolor($img)) {
|
|
$img1 = imagecreatetruecolor($x1, $y1);
|
|
} else {
|
|
$img1 = imagecreate($x1, $y1);
|
|
}
|
|
imagecopyresized($img1, $img, 0, 0, 0, 0, $x1, $y1, $x, $y);
|
|
|
|
// Build the new picture object
|
|
$pic1 = array();
|
|
$pic1["width"] = $x1;
|
|
$pic1["height"] = $y1;
|
|
$pic1["ratio"] = 1;
|
|
// GIF not supported, and should be replaced with PNG
|
|
$pic1["type"] = ($type == "image/gif")? "image/png": $type;
|
|
|
|
// Picture content
|
|
ob_start();
|
|
switch ($pic1["type"]) {
|
|
case "image/png":
|
|
imagepng($img1);
|
|
break;
|
|
case "image/jpeg":
|
|
imagejpeg($img1);
|
|
break;
|
|
}
|
|
$pic1["content"] = ob_get_contents();
|
|
ob_end_clean();
|
|
|
|
// Save the result
|
|
$sn1 = suspend_pic($pic1);
|
|
$pic["resized"][$ratio_s] = $sn1;
|
|
|
|
return $pic1;
|
|
}
|
|
|
|
// duppic: Duplicate a picture
|
|
function duppic($sn)
|
|
{
|
|
if (!pic_exists($sn)) {
|
|
return null;
|
|
}
|
|
$PICS =& pic_deposit();
|
|
// Generate a new random picture ID
|
|
$newsn = new_sn_assoc($PICS);
|
|
$PICS[$newsn] = $PICS[$sn];
|
|
$PICS[$newsn]["sn"] = $newsn;
|
|
return $newsn;
|
|
}
|
|
|
|
// pic_deposit: Return the picture deposit
|
|
function &pic_deposit()
|
|
{
|
|
// Session in use
|
|
if (isset($_SESSION)) {
|
|
if (!array_key_exists("savepics", $_SESSION)) {
|
|
$_SESSION["savepics"] = array();
|
|
}
|
|
return $_SESSION["savepics"];
|
|
|
|
// Session not in use
|
|
} else {
|
|
static $PICS = array();
|
|
return $PICS;
|
|
}
|
|
}
|
|
|
|
// clear_pic_deposit: Clear the picture deposit
|
|
function clear_pic_deposit()
|
|
{
|
|
$PICS =& pic_deposit();
|
|
$PICS = array();
|
|
return;
|
|
}
|
|
|
|
// piccache: Return an appropriate picture cache
|
|
function &piccache($table)
|
|
{
|
|
$PICS =& pic_deposit();
|
|
// Package specified
|
|
$package = defined("PACKAGE")? PACKAGE: REQUEST_HOST;
|
|
if (!array_key_exists("_cache", $PICS)) {
|
|
$PICS["_cache"] = array();
|
|
}
|
|
if (!array_key_exists($package, $PICS["_cache"])) {
|
|
$PICS["_cache"][$package] = array();
|
|
}
|
|
if (!array_key_exists($table, $PICS["_cache"][$package])) {
|
|
$PICS["_cache"][$package][$table] = array();
|
|
}
|
|
return $PICS["_cache"][$package][$table];
|
|
}
|
|
|
|
|
|
/////////////////////////
|
|
// Picture source operation in the SQL database
|
|
/////////////////////////
|
|
// readpic_content: Read a picture from its content into the picture deposit
|
|
// and return the picid
|
|
function readpic_content($data, $args, $sn, $table)
|
|
{
|
|
// Check the cache
|
|
$PICS =& pic_deposit();
|
|
$piccache =& piccache($table);
|
|
|
|
// Cached
|
|
if ( array_key_exists($sn, $piccache)
|
|
&& $data == $PICS[$piccache[$sn]]["content"]) {
|
|
$picid = $piccache[$sn];
|
|
$pic =& $PICS[$picid];
|
|
|
|
} else {
|
|
// Create the picture
|
|
$pic = array();
|
|
$pic["content"] = $data;
|
|
$pic["type"] = pictype_from_content($data);
|
|
|
|
// Set its width and height value
|
|
$img = imagecreatefromstring($pic["content"]);
|
|
$pic["width"] = imagesx($img);
|
|
$pic["height"] = imagesy($img);
|
|
|
|
// Suspend the created picture
|
|
$picid = suspend_pic($pic);
|
|
$piccache[$sn] = $picid;
|
|
}
|
|
|
|
// Check the wanted ratio
|
|
$ratio = 1;
|
|
if (is_null($args)) {
|
|
} elseif (array_key_exists("ratio", $args)) {
|
|
$ratio = $args["ratio"];
|
|
} elseif (array_key_exists("width", $args)) {
|
|
$ratio = $args["width"] / $pic["width"];
|
|
} elseif (array_key_exists("height", $args)) {
|
|
$ratio = $args["height"] / $pic["height"];
|
|
} elseif (array_key_exists("max", $args)) {
|
|
$ratio = $args["max"] / max($pic["width"], $pic["height"]);
|
|
}
|
|
|
|
// Check the ratio
|
|
// No ratio previously
|
|
if (!array_key_exists("ratio", $pic)) {
|
|
$pic["ratio"] = $ratio;
|
|
return $picid;
|
|
// Same ratio -- return the same picture
|
|
} elseif($pic["ratio"] == $ratio) {
|
|
return $picid;
|
|
// Ratio changed
|
|
} else {
|
|
$newpicid = duppic($picid);
|
|
$PICS[$newpicid]["ratio"] = $ratio;
|
|
$piccache[$sn] = $newpicid;
|
|
return $newpicid;
|
|
}
|
|
}
|
|
|
|
|
|
/////////////////////////
|
|
// Picture source operation on the file system.
|
|
// To be removed.
|
|
/////////////////////////
|
|
// readpic_pathprefix: Read a picture from a file into the picture deposit
|
|
// and return the picid
|
|
function readpic_pathprefix($prefix)
|
|
{
|
|
// Check each suffixes
|
|
$found = false;
|
|
foreach ($GLOBALS["PIC_VALID_SUFS"] as $suf) {
|
|
// Check if file exists
|
|
$file = "$prefix.$suf";
|
|
if ( !file_exists($file)
|
|
|| !is_readable($file)) {
|
|
continue;
|
|
}
|
|
// Check the MIME type
|
|
$type = check_mime_type($file);
|
|
if (!in_array($type, $GLOBALS["PIC_VALID_TYPES"])) {
|
|
continue;
|
|
}
|
|
// Found
|
|
$found = true;
|
|
break;
|
|
}
|
|
// Not found
|
|
if (!$found) {
|
|
return null;
|
|
}
|
|
|
|
// Read the picture
|
|
$pic = array();
|
|
$pic["content"] = xfread($file);
|
|
$pic["type"] = $type;
|
|
$img = imagecreatefromstring($pic["content"]);
|
|
$pic["width"] = imagesx($img);
|
|
$pic["height"] = imagesy($img);
|
|
$pic["ratio"] = 1;
|
|
$picid = suspend_pic($pic);
|
|
|
|
return $picid;
|
|
}
|
|
|
|
?>
|