Files
selima-perl/lib/php/monica/pic.inc.php
2026-03-10 21:31:43 +08:00

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;
}
?>