<?php
//=======================================================================
// File:    JPGRAPH.PHP
// Description:    PHP Graph Plotting library. Base module.
// Created:     2001-01-08
// Author:    Johan Persson (johanp@aditus.nu)
// Ver:        $Id: jpgraph.php 553 2006-02-18 07:45:05Z ljp $
//
// Copyright (c) Aditus Consulting. All rights reserved.
//========================================================================

require_once('jpg-config.inc.php');

// Version info
DEFINE('JPG_VERSION','2.1');

// For internal use only
DEFINE("_JPG_DEBUG",false);
DEFINE("_FORCE_IMGTOFILE",false);
DEFINE("_FORCE_IMGDIR",'/tmp/jpgimg/');


// Should the image be a truecolor image? 
// Note 1: Has only effect with GD 2.0.1 and above.
// Note 2: GD 2.0.1 + PHP 4.0.6 on Win32 crashes when trying to use 
// trucolor.
// Note 3: MUST be enabled to get background images working with GD2
DEFINE('USE_TRUECOLOR',true);

//------------------------------------------------------------------------
// Automatic settings of path for cache and font directory
// if they have not been previously specified
//------------------------------------------------------------------------
if(USE_CACHE) {
    if (!
defined('CACHE_DIR')) {
    if ( 
strstrPHP_OS'WIN') ) {
        if( empty(
$_SERVER['TEMP']) ) {
        
$t = new ErrMsgText();
        
$msg $t->Get(11,$file,$lineno);
        die(
$msg);
        }
        else {
        
DEFINE('CACHE_DIR'$_SERVER['TEMP'] . '/');
        }
    } else {
        
DEFINE('CACHE_DIR','/tmp/jpgraph_cache/');
    }
    }
}
elseif( !
defined('CACHE_DIR') ) {
    
DEFINE('CACHE_DIR''');
}

if (!
defined('TTF_DIR')) {
    if (
strstrPHP_OS'WIN') ) {
    
$sroot getenv('SystemRoot');
        if( empty(
$sroot) ) {
        
$t = new ErrMsgText();
        
$msg $t->Get(12,$file,$lineno);
        die(
$msg);
        }
    else {
      
DEFINE('TTF_DIR'$sroot.'/fonts/');
        }
    } else {
    
DEFINE('TTF_DIR','/usr/X11R6/lib/X11/fonts/truetype/');
    }
}

//------------------------------------------------------------------
// Constants which are used as parameters for the method calls
//------------------------------------------------------------------

// TTF Font families
// Note: First font must be FF_COURIER and the last font family must
// be given to _LAST_FONT. This is used for error checking in the text
// handling routines.
DEFINE("FF_COURIER",10);
DEFINE("FF_VERDANA",11);
DEFINE("FF_TIMES",12);
DEFINE("FF_COMIC",14);
DEFINE("FF_ARIAL",15);
DEFINE("FF_GEORGIA",16);
DEFINE("FF_TREBUCHE",17);

// Gnome Vera font
// Available from http://www.gnome.org/fonts/
DEFINE("FF_VERA",18);
DEFINE("FF_VERAMONO",19);
DEFINE("FF_VERASERIF",20);

// Chinese font
DEFINE("FF_SIMSUN",30);
DEFINE("FF_CHINESE",31);
DEFINE("FF_BIG5",31);

// Japanese font
DEFINE("FF_MINCHO",40);
DEFINE("FF_PMINCHO",41);
DEFINE("FF_GOTHIC",42);
DEFINE("FF_PGOTHIC",43);

// Limits for fonts
DEFINE("_FIRST_FONT",10);
DEFINE("_LAST_FONT",43);

// TTF Font styles
DEFINE("FS_NORMAL",9001);
DEFINE("FS_BOLD",9002);
DEFINE("FS_ITALIC",9003);
DEFINE("FS_BOLDIT",9004);
DEFINE("FS_BOLDITALIC",9004);

//Definitions for internal font, new style
DEFINE("FF_FONT0",1);
DEFINE("FF_FONT1",2);
DEFINE("FF_FONT2",4);

// Tick density
DEFINE("TICKD_DENSE",1);
DEFINE("TICKD_NORMAL",2);
DEFINE("TICKD_SPARSE",3);
DEFINE("TICKD_VERYSPARSE",4);

// Side for ticks and labels. 
DEFINE("SIDE_LEFT",-1);
DEFINE("SIDE_RIGHT",1);
DEFINE("SIDE_DOWN",-1);
DEFINE("SIDE_BOTTOM",-1);
DEFINE("SIDE_UP",1);
DEFINE("SIDE_TOP",1);

// Legend type stacked vertical or horizontal
DEFINE("LEGEND_VERT",0);
DEFINE("LEGEND_HOR",1);

// Mark types for plot marks
DEFINE("MARK_SQUARE",1);
DEFINE("MARK_UTRIANGLE",2);
DEFINE("MARK_DTRIANGLE",3);
DEFINE("MARK_DIAMOND",4);
DEFINE("MARK_CIRCLE",5);
DEFINE("MARK_FILLEDCIRCLE",6);
DEFINE("MARK_CROSS",7);
DEFINE("MARK_STAR",8);
DEFINE("MARK_X",9);
DEFINE("MARK_LEFTTRIANGLE",10);
DEFINE("MARK_RIGHTTRIANGLE",11);
DEFINE("MARK_FLASH",12);
DEFINE("MARK_IMG",13);
DEFINE("MARK_FLAG1",14);
DEFINE("MARK_FLAG2",15);
DEFINE("MARK_FLAG3",16);
DEFINE("MARK_FLAG4",17);

// Builtin images
DEFINE("MARK_IMG_PUSHPIN",50);
DEFINE("MARK_IMG_SPUSHPIN",50);
DEFINE("MARK_IMG_LPUSHPIN",51);
DEFINE("MARK_IMG_DIAMOND",52);
DEFINE("MARK_IMG_SQUARE",53);
DEFINE("MARK_IMG_STAR",54);
DEFINE("MARK_IMG_BALL",55);
DEFINE("MARK_IMG_SBALL",55);
DEFINE("MARK_IMG_MBALL",56);
DEFINE("MARK_IMG_LBALL",57);
DEFINE("MARK_IMG_BEVEL",58);

// Inline defines
DEFINE("INLINE_YES",1);
DEFINE("INLINE_NO",0);

// Format for background images
DEFINE("BGIMG_FILLPLOT",1);
DEFINE("BGIMG_FILLFRAME",2);
DEFINE("BGIMG_COPY",3);
DEFINE("BGIMG_CENTER",4);

// Depth of objects
DEFINE("DEPTH_BACK",0);
DEFINE("DEPTH_FRONT",1);

// Direction
DEFINE("VERTICAL",1);
DEFINE("HORIZONTAL",0);


// Axis styles for scientific style axis
DEFINE('AXSTYLE_SIMPLE',1);
DEFINE('AXSTYLE_BOXIN',2);
DEFINE('AXSTYLE_BOXOUT',3);
DEFINE('AXSTYLE_YBOXIN',4);
DEFINE('AXSTYLE_YBOXOUT',5);

// Style for title backgrounds
DEFINE('TITLEBKG_STYLE1',1);
DEFINE('TITLEBKG_STYLE2',2);
DEFINE('TITLEBKG_STYLE3',3);
DEFINE('TITLEBKG_FRAME_NONE',0);
DEFINE('TITLEBKG_FRAME_FULL',1);
DEFINE('TITLEBKG_FRAME_BOTTOM',2);
DEFINE('TITLEBKG_FRAME_BEVEL',3);
DEFINE('TITLEBKG_FILLSTYLE_HSTRIPED',1);
DEFINE('TITLEBKG_FILLSTYLE_VSTRIPED',2);
DEFINE('TITLEBKG_FILLSTYLE_SOLID',3);

// Style for background gradient fills
DEFINE('BGRAD_FRAME',1);
DEFINE('BGRAD_MARGIN',2);
DEFINE('BGRAD_PLOT',3);

// Width of tab titles
DEFINE('TABTITLE_WIDTHFIT',0);
DEFINE('TABTITLE_WIDTHFULL',-1);

// Defines for 3D skew directions
DEFINE('SKEW3D_UP',0);
DEFINE('SKEW3D_DOWN',1);
DEFINE('SKEW3D_LEFT',2);
DEFINE('SKEW3D_RIGHT',3);

// Line styles
DEFINE('LINESTYLE_DOTTED',1);
DEFINE('LINESTYLE_DASHED',2);
DEFINE('LINESTYLE_LONGDASH',3);
DEFINE('LINESTYLE_SOLID',4);

//
// Get hold of gradient class (In Version 2.x)
//
require_once 'jpgraph_gradient.php';

GLOBAL 
$__jpg_err_locale ;
$__jpg_err_locale 'en';
class 
ErrMsgText {
    private 
$lt=NULL;
    private 
$supportedLocales = array('en');
    function 
ErrMsgText() {
    GLOBAL 
$__jpg_err_locale;
    if( !
in_array($__jpg_err_locale,$this->supportedLocales) )
        
$aLoc 'en';
    require_once(
'lang/'.$__jpg_err_locale.'.inc.php');
    
$this->lt $_jpg_messages;
    }

    function 
Get($errnbr,$a1=null,$a2=null,$a3=null,$a4=null,$a5=null) {
    if( !isset(
$this->lt[$errnbr]) ) {
        return 
'Internal error: The specified error message does not exist in the chosen locale. (Please blame the translator...))';
    }
    
$ea $this->lt[$errnbr];
    
$j=0;
    if( 
$a1 !== null ) {
        
$argv[$j++] = $a1;
        if( 
$a2 !== null ) {
        
$argv[$j++] = $a2;
        if( 
$a3 !== null ) {
            
$argv[$j++] = $a3;
            if( 
$a4 !== null ) {
            
$argv[$j++] = $a4;
            if( 
$a5 !== null ) {
                
$argv[$j++] = $a5;
            }
            }
        }
        }
    }
    
$numargs $j
    if( 
$ea[1] != $numargs ) {
        
// Error message argument count do not match.
        // Just return the error message without arguments.
        
return $ea[0];
    }
    switch( 
$numargs ) {
        case 
1:
        
$msg sprintf($ea[0],$argv[0]);
        break;
        case 
2:
        
$msg sprintf($ea[0],$argv[0],$argv[1]);
        break;
        case 
3:
        
$msg sprintf($ea[0],$argv[0],$argv[1],$argv[2]);
        break;
        case 
4:
        
$msg sprintf($ea[0],$argv[0],$argv[1],$argv[2],$argv[3]);
        break;
        case 
5:
        
$msg sprintf($ea[0],$argv[0],$argv[1],$argv[2],$argv[3],$argv[4]);
        break;
        case 
0:
        default:
        
$msg sprintf($ea[0]);
        break;
    }
    return 
$msg;
    }
}

//
// A wrapper class that is used to access the specified error object
// (to hide the global error parameter and avoid having a GLOBAL directive
// in all methods.
//
class JpGraphError {
    private static 
$__jpg_err;
    public static function 
Install($aErrObject) {
    
self::$__jpg_err = new $aErrObject;
    }
    public static function 
Raise($aMsg,$aHalt=true){
    
self::$__jpg_err->Raise($aMsg,$aHalt);
    }
    public static function 
RaiseL($errnbr,$a1=null,$a2=null,$a3=null,$a4=null,$a5=null) {
    
$t = new ErrMsgText();
    
$msg $t->Get($errnbr,$a1,$a2,$a3,$a4,$a5);
    
self::$__jpg_err->Raise($msg);
    }
}
 
//
// ... and install the default error handler
//
if( USE_IMAGE_ERROR_HANDLER ) {
    
JpGraphError::Install("JpGraphErrObjectImg");
}
else {
    
JpGraphError::Install("JpGraphErrObject");
}

//
// Make GD sanity check
//
if( !function_exists("imagetypes") || !function_exists('imagecreatefromstring') ) {
    
JpGraphError::RaiseL(25001);
//("This PHP installation is not configured with the GD library. Please recompile PHP with GD support to run JpGraph. (Neither function imagetypes() nor imagecreatefromstring() does exist)");
}

//
// First of all set up a default error handler
//

//=============================================================
// The default trivial text error handler.
//=============================================================
class JpGraphErrObject {

    protected 
$iTitle "JpGraph Error";
    protected 
$iDest false;


    function 
JpGraphErrObject() {
    
// Empty. Reserved for future use
    
}

    function 
SetTitle($aTitle) {
    
$this->iTitle $aTitle;
    }

    function 
SetStrokeDest($aDest) { 
    
$this->iDest $aDest
    }

    
// If aHalt is true then execution can't continue. Typical used for fatal errors
    
function Raise($aMsg,$aHalt=true) {
    
$aMsg $this->iTitle.' '.$aMsg;
    if (
$this->iDest) {
        
$f = @fopen($this->iDest,'a');
        if( 
$f ) {
        @
fwrite($f,$aMsg);
        @
fclose($f);
        }
    }
    else {
        echo 
$aMsg;
    }
    if( 
$aHalt )
        die();
    }
}

//==============================================================
// An image based error handler
//==============================================================
class JpGraphErrObjectImg extends JpGraphErrObject {

    function 
Raise($aMsg,$aHalt=true) {
    
$img_iconerror 
        
'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAMAAAC7IEhfAAAAaV'.
        
'BMVEX//////2Xy8mLl5V/Z2VvMzFi/v1WyslKlpU+ZmUyMjEh/'.
        
'f0VyckJlZT9YWDxMTDjAwMDy8sLl5bnY2K/MzKW/v5yyspKlpY'.
        
'iYmH+MjHY/PzV/f2xycmJlZVlZWU9MTEXY2Ms/PzwyMjLFTjea'.
        
'AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACx'.
        
'IAAAsSAdLdfvwAAAAHdElNRQfTBgISOCqusfs5AAABLUlEQVR4'.
        
'2tWV3XKCMBBGWfkranCIVClKLd/7P2Q3QsgCxjDTq+6FE2cPH+'.
        
'xJ0Ogn2lQbsT+Wrs+buAZAV4W5T6Bs0YXBBwpKgEuIu+JERAX6'.
        
'wM2rHjmDdEITmsQEEmWADgZm6rAjhXsoMGY9B/NZBwJzBvn+e3'.
        
'wHntCAJdGu9SviwIwoZVDxPB9+Rc0TSEbQr0j3SA1gwdSn6Db0'.
        
'6Tm1KfV6yzWGQO7zdpvyKLKBDmRFjzeB3LYgK7r6A/noDAfjtS'.
        
'IXaIzbJSv6WgUebTMV4EoRB8a2mQiQjgtF91HdKDKZ1gtFtQjk'.
        
'YcWaR5OKOhkYt+ZsTFdJRfPAApOpQYJTNHvCRSJR6SJngQadfc'.
        
'vd69OLMddVOPCGVnmrFD8bVYd3JXfxXPtLR/+mtv59/ALWiiMx'.
        
'qL72fwAAAABJRU5ErkJggg==' ;

    if( 
function_exists("imagetypes") )
        
$supported imagetypes();
    else
        
$supported 0;

    if( !
function_exists('imagecreatefromstring') )
        
$supported 0;

    if( 
ob_get_length() || headers_sent() || !($supported IMG_PNG) ) {
        
// Special case for headers already sent or that the installation doesn't support
        // the PNG format (which the error icon is encoded in). 
        // Dont return an image since it can't be displayed
        
die($this->iTitle.' '.$aMsg);        
    }

    
$aMsg wordwrap($aMsg,55);
    
$lines substr_count($aMsg,"\n");

    
// Create the error icon GD
    
$erricon Image::CreateFromString(base64_decode($img_iconerror));   

    
// Create an image that contains the error text.
    
$w=400;     
    
$h=100 15*max(0,$lines-3);

    
$img = new Image($w,$h);


    
// Drop shadow
    
$img->SetColor("gray");
    
$img->FilledRectangle(5,5,$w-1,$h-1,10);
    
$img->SetColor("gray:0.7");
    
$img->FilledRectangle(5,5,$w-3,$h-3,10);
    
    
// Window background
    
$img->SetColor("lightblue");
    
$img->FilledRectangle(1,1,$w-5,$h-5);
    
$img->CopyCanvasH($img->img,$erricon,5,30,0,0,40,40);

    
// Window border
    
$img->SetColor("black");
    
$img->Rectangle(1,1,$w-5,$h-5);
    
$img->Rectangle(0,0,$w-4,$h-4);
    
    
// Window top row
    
$img->SetColor("darkred");
    for(
$y=3$y 18$y += 
        
$img->Line(1,$y,$w-6,$y);

    
// "White shadow"
    
$img->SetColor("white");

    
// Left window edge
    
$img->Line(2,2,2,$h-5);
    
$img->Line(2,2,$w-6,2);

    
// "Gray button shadow"
    
$img->SetColor("darkgray");

    
// Gray window shadow
    
$img->Line(2,$h-6,$w-5,$h-6);
    
$img->Line(3,$h-7,$w-5,$h-7);

    
// Window title
    
$m floor($w/2-5);
    
$l 100;
    
$img->SetColor("lightgray:1.3");
    
$img->FilledRectangle($m-$l,2,$m+$l,16);

    
// Stroke text
    
$img->SetColor("darkred");
    
$img->SetFont(FF_FONT2,FS_BOLD);
    
$img->StrokeText($m-50,15,$this->iTitle);
    
$img->SetColor("black");
    
$img->SetFont(FF_FONT1,FS_NORMAL);
    
$txt = new Text($aMsg,52,25);
    
$txt->Align("left","top");
    
$txt->Stroke($img);
    if (
$this->iDest) {
           
$img->Stream($this->iDest);
    } else {
        
$img->Headers();
        
$img->Stream();
    }
    if( 
$aHalt )
        die();
    }
}

//
// Setup PHP error handler
//
function _phpErrorHandler($errno,$errmsg,$filename$linenum$vars) {
    
// Respect current error level
    
if( $errno error_reporting() ) {
    
JpGraphError::RaiseL(25003,basename($filename),$linenum,$errmsg); 
    }
}

if( 
INSTALL_PHP_ERR_HANDLER ) {
    
set_error_handler("_phpErrorHandler");
}

//
//Check if there were any warnings, perhaps some wrong includes by the
//user
//
if( isset($GLOBALS['php_errormsg']) && CATCH_PHPERRMSG && 
    !
preg_match('|Deprecated|'$GLOBALS['php_errormsg']) ) {
    
JpGraphError::RaiseL(25004,$GLOBALS['php_errormsg']);
}


// Useful mathematical function
function sign($a) {return $a >= : -1;}

// Utility function to generate an image name based on the filename we
// are running from and assuming we use auto detection of graphic format
// (top level), i.e it is safe to call this function
// from a script that uses JpGraph
function GenImgName() {
    
// Determine what format we should use when we save the images
    
$supported imagetypes();
    if( 
$supported IMG_PNG )       $img_format="png";
    elseif( 
$supported IMG_GIF $img_format="gif";
    elseif( 
$supported IMG_JPG $img_format="jpeg";

    if( !isset(
$_SERVER['PHP_SELF']) )
    
JpGraphError::RaiseL(25005);
//(" Can't access PHP_SELF, PHP global variable. You can't run PHP from command line if you want to use the 'auto' naming of cache or image files.");
    
$fname basename($_SERVER['PHP_SELF']);
    if( !empty(
$_SERVER['QUERY_STRING']) ) {
    
$q = @$_SERVER['QUERY_STRING'];
    
$fname .= '?'.preg_replace("/\W/""_"$q).'.'.$img_format;
    }
    else {
    
$fname substr($fname,0,strlen($fname)-4).'.'.$img_format;
    }
    return 
$fname;
}

class 
LanguageConv {
    private 
$g2312 null ;

    function 
Convert($aTxt,$aFF) {
    if( 
LANGUAGE_CYRILLIC ) {
        if( 
CYRILLIC_FROM_WINDOWS ) {
        
$aTxt convert_cyr_string($aTxt"w""k"); 
        }
        
$isostring convert_cyr_string($aTxt"k""i");
        
$unistring LanguageConv::iso2uni($isostring);
        return 
$unistring;
    }
    elseif( 
$aFF === FF_SIMSUN ) {
        
// Do Chinese conversion
        
if( $this->g2312 == null ) {
        include_once 
'jpgraph_gb2312.php' ;
        
$this->g2312 = new GB2312toUTF8();
        }
        return 
$this->g2312->gb2utf8($aTxt);
    }
    elseif( 
$aFF === FF_CHINESE ) {
        if( !
function_exists('iconv') ) {
        
JpGraphError::RaiseL(25006);
//('Usage of FF_CHINESE (FF_BIG5) font family requires that your PHP setup has the iconv() function. By default this is not compiled into PHP (needs the "--width-iconv" when configured).');
        
}
        return 
iconv('BIG5','UTF-8',$aTxt);
    }
    else 
        return 
$aTxt;
    }

    
// Translate iso encoding to unicode
    
function iso2uni ($isoline){
    
$uniline='';
    for (
$i=0$i strlen($isoline); $i++){
        
$thischar=substr($isoline,$i,1);
        
$charcode=ord($thischar);
        
$uniline.=($charcode>175) ? "&#" . (1040+($charcode-176)). ";" $thischar;
    }
    return 
$uniline;
    }
}

//===================================================
// CLASS JpgTimer
// Description: General timing utility class to handle
// time measurement of generating graphs. Multiple
// timers can be started.
//===================================================
class JpgTimer {
    private 
$start$idx;    
//---------------
// CONSTRUCTOR
    
function JpgTimer() {
    
$this->idx=0;
    }

//---------------
// PUBLIC METHODS    

    // Push a new timer start on stack
    
function Push() {
    list(
$ms,$s)=explode(" ",microtime());    
    
$this->start[$this->idx++]=floor($ms*1000) + 1000*$s;    
    }

    
// Pop the latest timer start and return the diff with the
    // current time
    
function Pop() {
    
assert($this->idx>0);
    list(
$ms,$s)=explode(" ",microtime());    
    
$etime=floor($ms*1000) + (1000*$s);
    
$this->idx--;
    return 
$etime-$this->start[$this->idx];
    }
// Class

$gJpgBrandTiming BRAND_TIMING;
//===================================================
// CLASS DateLocale
// Description: Hold localized text used in dates
//===================================================
class DateLocale {
 
    public 
$iLocale 'C'// environmental locale be used by default
    
private $iDayAbb null$iShortDay null$iShortMonth null$iMonthName null;

//---------------
// CONSTRUCTOR    
    
function DateLocale() {
    
settype($this->iDayAbb'array');
    
settype($this->iShortDay'array');
    
settype($this->iShortMonth'array');
    
settype($this->iMonthName'array');


    
$this->Set('C');
    }

//---------------
// PUBLIC METHODS    
    
function Set($aLocale) {
    if ( 
in_array($aLocalearray_keys($this->iDayAbb)) ){ 
        
$this->iLocale $aLocale;
        return 
TRUE;  // already cached nothing else to do!
    
}

    
$pLocale setlocale(LC_TIME0); // get current locale for LC_TIME
    
$res = @setlocale(LC_TIME$aLocale);
    if ( ! 
$res ){
        
JpGraphError::RaiseL(25007,$aLocale);
//("You are trying to use the locale ($aLocale) which your PHP installation does not support. Hint: Use '' to indicate the default locale for this geographic region.");
        
return FALSE;
    }
 
    
$this->iLocale $aLocale;
    for ( 
$i 0$ofs strftime('%w'); $i 7$i++, $ofs++ ){
        
$day strftime('%a'strtotime("$ofs day"));
        
$day[0] = strtoupper($day[0]);
        
$this->iDayAbb[$aLocale][]= $day[0];
        
$this->iShortDay[$aLocale][]= $day;
    }

    for(
$i=1$i<=12; ++$i) {
        list(
$short ,$full) = explode('|'strftime("%b|%B",strtotime("2001-$i-01")));
        
$this->iShortMonth[$aLocale][] = ucfirst($short);
        
$this->iMonthName [$aLocale][] = ucfirst($full);
    }
        
    
setlocale(LC_TIME$pLocale);

    return 
TRUE;
    }


    function 
GetDayAbb() {
    return 
$this->iDayAbb[$this->iLocale];
    }
    
    function 
GetShortDay() {
    return 
$this->iShortDay[$this->iLocale];
    }

    function 
GetShortMonth() {
    return 
$this->iShortMonth[$this->iLocale];
    }
    
    function 
GetShortMonthName($aNbr) {
    return 
$this->iShortMonth[$this->iLocale][$aNbr];
    }

    function 
GetLongMonthName($aNbr) {
    return 
$this->iMonthName[$this->iLocale][$aNbr];
    }

    function