<? // PHPmyGallery - functions library

// Note: This functions library requires several
// functions for PHPmyGallery database access.


#######################################
### Script execution time functions ###
#######################################

// Inits execution time now. Not wrapped in a function
// so it`s as exactly as possible
list($usec, $sec) = explode(' ',microtime());  
$time_start = ((float)$usec + (float)$sec);

//  Global function                      _________________________                                 
//\_____________________________________/ Peter Krebs (PeKa)      \_____________________________   
///  pk_exectime                        \              2001-10-10 /                             \  
//                                       ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ                               \ 
// Function to calculate execution time at the end of the script (as seen in php.net/manual/)
// The function returns a string with the amount of seconds passed after $time_start,
// with the precision given by $precision. 
// It receives the start time as a float value (seconds) and returns the elapsed amount
// of seconds from then to now. Of course, the parameter $time_start should be in the
// past for this to work.
//  $dec_point is a PHP string containing the decimal point character, default is '.'
//  $precision tells the number of digits after the decimal point, default is 5
function pk_exectime($time_start,$dec_point='.',$precision=5) {
    list($usec, $sec) = explode(' ',microtime());  
    $time = ((float)$usec + (float)$sec) - $time_start;
    
    return number_format($time,$precision,$dec_point,'');
} // pk_exectime();


###########################
### Language packs etc. ###
###########################

//  Global function                      _________________________                                 
//\_____________________________________/ Peter Krebs (PeKa)      \_____________________________   
///  processLanguagePack                \              2006-01-12 /                             \  
//                                       ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ                               \ 
// Adds all entries from a $l array inside a language pack file to the pktpl_vars array.
// Example: $l['hello_wurld'] becomes $pktpl_vars['l_hello_wurld'] and can then be
// used in a template of your choice.
function processLanguagePack($langpackName,$lang,$langIfNotFound) {
    global $pktpl_vars,$admindir;
    global $l, $m, $tip;    // Arrays that can occur in a language pack. These must
                            // be initiated outside this function to be available, so
                            // they are made globally here (see common-tpl-vars.php).
    
    // Insert file and add $l array inside it to the pktpl_vars array
    require($admindir.'lang/'.$langpackName.'.'.$lang.'.php');
    foreach($l as $k=>$v) {
        $pktpl_vars['l_'.$k] = $v;
    } // foreach
} // processLanguagePack();


###############################
### Template system (pktpl) ###
###############################

//  Global function                      _________________________                                 
//\_____________________________________/ Peter Krebs (PeKa)      \_____________________________   
///  pktpl_start                        \              2001-10-10 /                             \  
//                                       ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ                               \
// Starts the template system. Simply returns an empty array.
// You may find this useless, but it's nice to start pktpl explicitely I think.
// Might involve more initialisation stuff in future versions. 
function pktpl_start() {
    return array();
} // pktpl_start();


//  Global function                      _________________________                                 
//\_____________________________________/ Peter Krebs (PeKa)      \_____________________________   
///  pktpl                              \              2001-10-10 /                             \  
//                                       ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ                               \
//  This is the HTML-template system which is used to generate HTML Websites.
// It receives a template filename as the first parameter. The file is parsed for pktpl
// variables and the finished template is returned as a string.
// pktpl variables look like this: {$name} (left curled brace, $ sign, any name and a right
// curled brace). Names may include - or _ but no spaces.
// If $pktpl_vars['name'] has content, {$name} is substituted by this content, otherwise
// {$name} within a template is replaced with an empty string.
// If the file could not be found and the second parameter is set to true (default), a
// warning is returned as an HTML formatted string.
function pktpl($template,$report_warnings = true) {
    global $pktpl_vars,$admindir;
    global $picdir,$group;
    
    $errormessage_template = 'templates/'.$template; // Used in error message so the admin directory doesn't show
    
    if($group != '' && $picdir != '' && is_file($group.'/'.$picdir.'/'.$template))
        $template = $group.'/'.$picdir.'/'.$template;
    else
        $template = $admindir.'templates/'.$template;
    
    if (!is_dir($template) && is_file($template)) {
        $string = implode('',file($template));
        $string = preg_replace('/\{\$([a-zA-Z0-9\_\-\.]*)\}/e','$pktpl_vars[\'\\1\']',$string);
        return $string;
    } // if
    else {
        if($report_warnings)
            return '<span class="error">&nbsp;<b>Error:</b> '.$errormessage_template.' is no file in this directory.&nbsp;</span>';
    } // else
    
} // pktpl();


###############################################################
### Internal functions (mostly used within functions below) ###
###############################################################

//  Global function                      _________________________                                 
//\_____________________________________/ Peter Krebs (PeKa)      \_____________________________   
///  filenames2arr                      \              2005-05-23 /                             \  
//                                       ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ                               \
//  Receives a directory name ($dir) and a parameter $addMode that tells which type of file
// to process. The function returnes an array of filenames.
// Available modes are: IMAGES, GROUPS, DIRECTORIES and PLUGINS.
function filenames2arr($dir,$addMode) {
    global $conf, $debugText;
    
    // Read directory
    
    $filenameArr = array();
    $arr = array();
    if(is_dir($dir)) {
        $dirObj = dir($dir);
        while ($add = $dirObj->read()) {
            // Reset bool variable which will be used to decide if $add will be added to $arr
            $addingGranted = false;
            
            // Exclude hidden and explicitly excluded files in any case
            $hidden             = (substr($add,0,1)=='-'||substr($add,0,1)=='_');
            $filenameArr        = explode('.',$add);
            $isExcludedFilename = ($add == '.' || $add == '..' ||
                                   in_array($filenameArr[0],$conf['excluded_filenames']));
            
            // If file/directory is hidden or is within the list
            // of excluded filenames, proceed to next one
            if($hidden || $isExcludedFilename)
                continue;
            
            // Set $addingGranted according to $addMode
            switch($addMode) {
                // Check for images
                case IMAGES:
                    // Gets the thumbnail prefix/suffix and tests for occurance
                    $ext         = strtolower($filenameArr[count($filenameArr)-1]);
                    $isPicture   = (in_array($ext,$conf['picture_extensions']));
                    
                    // Get rid of filename extension
                    unset( $filenameArr[count($filenameArr)-1] );
                    $pic = implode('.',$filenameArr);
                    
                    // Test if its a thumbnail
                    if ($conf['prefix_or_suffix']=='prefix') {
                        $isThumbnail = (substr($pic,0,strlen($conf['thumb_prefix'])) == $conf['thumb_prefix']);
                    } // if
                    else {
                        $isThumbnail = (substr($pic,-1*strlen($conf['thumb_suffix']),
                                                       strlen($conf['thumb_suffix'])) == $conf['thumb_suffix']);
                    } // else
                    
                    // set $addingGranted according to the criteria
                    $addingGranted = ($isPicture&&!$isThumbnail);
                break;
                // Check for directories or groups
                case GROUPS:
                case DIRECTORIES:
                    // Sets criteria to add a directory or group to $arr
                    $isDir = (is_dir($dir.$add));
                    
                    // set $addingGranted according to the criteria
                    $addingGranted = ($isDir);
                break;
                case PLUGINS:
                    // Sets criteria to add a plugin filename
                    $isFile   = (!is_dir($dir.$add) && is_file($dir.$add));
                    $isPlugin = (substr($add,-4,4)=='.php');
                    
                    // set $addingGranted according to the criteria
                    $addingGranted = ($isFile&&$isPlugin);
                break;
            } // switch
            
            // Uncomment to debug last call
            /*$debugText = 'File: '.$dir.$add.'<br>'.
                  '!$hidden->'.!$hidden.'<br>'.
                  '$isNoExcludedFilename->'.$isNoExcludedFilename.'<br>'.
                  '$isPicture->'.$isPicture.'<br>'.
                  '$isNoThumbnail->'.$isNoThumbnail.'<br>'.
                  '$isDir->'.$isDir.'<br><br>';
                  '$isPlugin->'.$isPlugin.'<br><br>';
            */
            
            // Adds the filename to $arr, if file matches the $addMode type
            if ($addingGranted) {
                array_push($arr, $add);
            } // if
        } // while
    } // if
    else {
        $debugText = 'Warning: "'.$dir.'" is not a directory.';
    } // else
    
    // Returns sorted $arr (with natural sorting algorythm,
    // so it lists 1,2,3,...,10 and not 1,10,2,3,...)
    natsort($arr);
    return $arr;
} // filenames2arr();


//  Global function                      _________________________                                 
//\_____________________________________/ Peter Krebs (PeKa)      \_____________________________   
///  filename_encode                    \              2001-10-10 /                             \  
//                                       ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ                               \
//  Used to change . - etc. in filenames to text. Mainly used for HTML forms to
// automatically generate a name attribute.
function filename_encode($filename,$reverse = false) {
    global $conf;
    $fileencode = array(
        '.'=>'__DOT__',
        '-'=>'__MINUS__',
        ' '=>'__SPACE__'
    );
    
    if ($reverse==true) {
        $fileencode = array_flip($fileencode);
    } // if
    
    foreach($fileencode as $from=>$to) {
        $filename = str_replace($from,$to,$filename);
    } // foreach
    
    return $filename;
} // filename_encode();


//  Global function                      _________________________                                 
//\_____________________________________/ Peter Krebs (PeKa)      \_____________________________   
///  filename_decode                    \              2001-10-10 /                             \  
//                                       ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ                               \
//  Used to change filenames generated by filename_encode back to the original
function filename_decode($filename) {
    $filename = filename_encode($filename,true);
    return $filename;
} // filename_decode();


//  Global function                      _________________________                                 
//\_____________________________________/ Peter Krebs (PeKa)      \_____________________________   
///  findArrayNeighbourhood             \              2005-03-01 /                             \  
//                                       ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ                               \
//  Receives a one-dimensional array and a value from this array.
// The function returns the first and last value of the array and the value
// previous and next to the given value. Will only find the first occurance
// of the given value.
// Keys of the array MUST be ascending ordered numbers (0,1,2,3,...).
function findArrayNeighbourhood($givenArr,$givenValue) {
    global $conf;
    
    // Init variables
    $returnArray = array();
    $firstValue  = $previousValue = $nextValue = $lastValue = '';
    $ValueFoundAt       = -1;               // Will be assigned the matching key for $value
    $ValueFoundAtNumber =  VALUENOTFOUND;   // Will be assigned the matching key number (counted from 1)
    
    $valueCount = count($givenArr);
    
    // Finds the last value of the array
    end($givenArr);
    $lastValue = current($givenArr);
    
    // Finds the first value of the array
    reset($givenArr);
    $firstValue = current($givenArr);
    
    // Finds the values previous and next to value
    // Sure, searching from the beginning of the array is quite slow if
    // $givenValue is way in the back of the array. But I don't expect
    // more than 100 or 200 array entries so it has a fair speed by now.
    // You should have seen the previous versions of the function - a MESS! :)
    $Number = 0;
    foreach($givenArr as $key=>$value) {
        // Adds 1 to $Number. If the value is found within the array,
        // $Number is assigned to $ValueFoundAtNumber 
        $Number++;
        
        // If $givenValue matches $value, we have a winner :)
        if ($value==$givenValue) {
            $ValueFoundAt       = $key;
            $ValueFoundAtNumber = $Number;
            
            // Get previous value
            if($Number > 1);
                $previousValue = $givenArr[$key-1];
            
            // Get next value
            if($Number < $valueCount)
                $nextValue = $givenArr[$key+1];
            
            break; // Stops the foreach loop, since we have what we want
        } // if
    } // foreach
    
    // Assign the key names found out to the returned array
    $returnArray[FIRSTVALUE]         = $firstValue;
    $returnArray[PREVIOUSVALUE]      = $previousValue;
    $returnArray[NEXTVALUE]          = $nextValue;
    $returnArray[LASTVALUE]          = $lastValue;
    $returnArray[VALUEFOUNDAT]       = $ValueFoundAt;
    $returnArray[VALUEFOUNDATNUMBER] = $ValueFoundAtNumber;
    
    return $returnArray;
} // findArrayNeighbourhood();


############################################
### PHP Code Functions (return PHP Code) ###
############################################

//  Global function                      _________________________                                 
//\_____________________________________/ Peter Krebs (PeKa)      \_____________________________   
///  arr2php                            \              2005-05-15 /                             \  
//                                       ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ                               \
//  Return PHP code from a PHP variable. Slashes are added to special characters automatically
// (\" for ", \\ for \ etc.), don't forget to call stripslashes when processing the data!
// This function is recursive, so it is able to handle multi-dimensional arrays.
// It does not support PHP objects yet.
function arr2php($var,$varname,$comma = ';') {
    global $conf;
    $nl = "\n";
    
    if($varname=='' && $comma==';') { // if $comma is ';' it should be the first call
        return '$error = \'arr2php - $varname not set. Please give me a variable name to work with ;D\';';
    }
    
    if (is_array($var)) {
        if ($varname!='') { // '$varname = ' should not be printed again if the
                                                // function has been called recursively
            $string = $nl.'$'.$varname.' = ';   // (see arr2php call within this function)
        } // if
        
        $string .= 'array('.$nl;
        foreach($var as $k=>$v) {
            // translate key (only strings and numbers
            if(is_string($k)) {
                // $k = addslashes($k); // Uncomment this line if you expect ', \ or " in the array's keys
                $string .= '\''.$k.'\'=>';
            } // if string
            else {
                $string .= $k.'=>';
            } // else
            
            // translate value
            if (is_bool($v)) {
                $string .= ($v) ? 'true,': 'false,';
            } // if bool
            elseif (is_array($v)) {
                $string .= arr2php($v,'',',');
            } // if array
            elseif(is_string($v)) {
                $v = addslashes($v);
                $string .= '\''.$v.'\','.$nl;
            } // elseif string
            elseif(is_numeric($v)) {
                $string .= $v.','.$nl;
            } // elseif number
            elseif($v===null) {
                $string .= ' = null; // on purpose?';
            } // elseif null
            else {
                $string .= ' = null; // could not be processed (unsupported type)';
            } // else exception
        } // foreach
        $string .= ')'.$comma.$nl;
    } // if array
    elseif (is_bool($var)) {
        $string = ($var) ? 'true;': 'false;';
    } // if bool
    elseif (is_string($var)) {
        $var = addslashes($var);
        $string = '$'.$varname.' = \''.$var.'\';';
    } // elseif string
    elseif (is_numeric($var)) {
        $string = '$'.$varname.' = '.$var.';';
    } // elseif number
    elseif($v===null) {
        $string = '$'.$varname.' = null; // on purpose?';
    } // elseif null
    else {
        $string = '$'.$varname.' = null; // could not be processed (unsupported type)';
    } // else
    
    return $string;
} // arr2php();


#################
### Debugging ###
#################

//  Global function                      _________________________                                 
//\_____________________________________/ Peter Krebs (PeKa)      \_____________________________   
///  debugBox                           \              2005-03-01 /                             \  
//                                       ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ                               \
//  Returns debugBox template for debug mode.
// debugText, debugTitle and pktpl_vars should exist for this to work.
function debugBox() {
    global $debugText,$conf,$l,$pktpl_vars;
    
    if (!isset($debugTitle) || $debugTitle=='') {
        $debugTitle = SCRIPT_NAME.' '.SCRIPT_VERSION.$conf['titleSeperator'].$l['debug_mode'];
    } // if
    
    if (is_array($debugText)) { $debugText = arr2php($debugText,'debugText'); }
    $debugText = str_replace("\n\n", "\n", $debugText);
    $debugText = str_replace(">", "&gt;", $debugText);
    $debugText = str_replace("<", "&lt;", $debugText);
    $debugText = nl2br($debugText);
    
    $pktpl_vars['debug_title'] = $debugTitle;
    $pktpl_vars['debug_text']  = $debugText;
   
    return pktpl('all_debugBox.html');
} // debugBox()


#######################################################
### Writer Functions (write data into the database) ###
#######################################################

//  Global function                      _________________________                                 
//\_____________________________________/ Peter Krebs (PeKa)      \_____________________________   
///  doStats                            \              2005-04-12 /                             \  
//                                       ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ                               \
//  Adds 1 to the statistics of the group, gallery or picture that $group, $picdir
// and $pic point to. Take a look in any statistics file for an overview of the file format.
// This function now checks if the file really exists (since 1.51.0 Gold) and returns true
// if this is the case. If the file does not exist (there), it returns false.
function doStats($group,$picdir,$pic) {
    global $debugText,$conf,$admindir;
    
    // Init temporary variables
    $dbEntry    = date('Y.m');
    $grp        = addslashes($group);
    $grpdir     = $grp.'/'.addslashes($picdir);
    $grpdirpics = $grpdir.'/'.addslashes($pic);
    $filename   = $group.'/'.$picdir.'/'.$pic;
    $filename   = str_replace('//','/',$filename);
    
    /* Load statistics for the current month */
    if(file_exists($filename)) {
        if (allocateData('statistics',$dbEntry)) {
            $data = getData('statistics',$dbEntry);
        } // if
        // If they don`t exist, create empty stats array
        else {
            $data = array();
            $data[STATS_GROUPS]    = array();
            $data[STATS_GALLERIES] = array();
            $data[STATS_PICS]      = array();
        } // else
        
        /* Process statistics data */
        if ($pic!='') {         // adds +1 to ['groupname/galleryname/picname']
            (int)$data[STATS_PICS][$grpdirpics] += 1;
        } // if
        elseif ($picdir!='') {  // adds +1 to ['groupname/galleryname']
            (int)$data[STATS_GALLERIES][$grpdir] += 1;
        } // elseif
        elseif ($group!='') {   // adds +1 to ['groupname']
            (int)$data[STATS_GROUPS][$grp] += 1;
        } // elseif
        
        /* Write stats file to database */
        putData($data,'statistics',$dbEntry);
        
        return true;
    } // if
    else {
        // Testing:
        //$debugText .= 'Statistics: Picture "'.$filename.'" not found.';
        return false;
    } // else
} // doStats();


#############################
### File system functions ###
#############################

//  Global function                      _________________________                                 
//\_____________________________________/ Peter Krebs (PeKa)      \_____________________________   
///  ChmodIs777                         \              2005-03-01 /                             \  
//                                       ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ                               \
//  Returns true if file`s CHMOD attributes are on 777, otherwise false
function ChmodIs777($file) {
    // get file permissions in octal, converted to string
    $perms = substr(base_convert(fileperms($file), 10, 8), -3);
    // store 777 (octal) in string
    $desiredperms = substr(sprintf('%o', 0777), -3);
    
    // Now look up if they match
    if ($perms == $desiredperms) {
        return true;
    } // if
    else {
        return false;
    } // else
    
} // ChmodIs777();


//  Global function                      _________________________                                 
//\_____________________________________/ Peter Krebs (PeKa)      \_____________________________   
///  statsfilesExist                    \              2005-04-11 /                             \  
//                                       ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ                               \
//  Look up if any statistics are available at all
function statfilesExist() {
    global $conf;
    
    if(tableEmpty('statistics'))
        return false;
    else
        return true;
    
} // statfilesExist();

//  Global function                      _________________________                                 
//\_____________________________________/ Peter Krebs (PeKa)      \_____________________________   
///  SetFilepermissions                 \              2005-03-01 /                             \  
//                                       ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ                               \
//  Set file permissions of a given array of files to 777.
// Will only work if PHP may use the chmod command. Chmod is not necessary on
// Windows systems, but won`t do any harm, too.
// An array of file or directory names is supplied to the function
function SetFilepermissions($array) {
    foreach($array as $filename)
        @chmod($filename,0777);
} // SetFilepermissions();

?>