forked from vergnet/site-accueil-insa
702 lines
16 KiB
PHP
702 lines
16 KiB
PHP
<?php
|
|
/**
|
|
* api: php
|
|
* title: upgrade.php
|
|
* description: Emulates functions from new PHP versions on older interpreters.
|
|
* version: 17
|
|
* license: Public Domain
|
|
* url: http://freshmeat.net/projects/upgradephp
|
|
* type: functions
|
|
* category: library
|
|
* priority: auto
|
|
* load_if: (PHP_VERSION<5.2)
|
|
* sort: -255
|
|
* provides: upgrade-php, api:php5, json
|
|
*
|
|
*
|
|
* By loading this library you get PHP version independence. It provides
|
|
* downwards compatibility to older PHP interpreters by emulating missing
|
|
* functions or constants using IDENTICAL NAMES. So this doesn't slow down
|
|
* script execution on setups where the native functions already exist. It
|
|
* is meant as quick drop-in solution. It spares you from rewriting code or
|
|
* using cumbersome workarounds instead of the more powerful v5 functions.
|
|
*
|
|
* It cannot mirror PHP5s extended OO-semantics and functionality into PHP4
|
|
* however. A few features are added here that weren't part of PHP yet. And
|
|
* some other function collections are separated out into the ext/ directory.
|
|
* It doesn't produce many custom error messages (YAGNI), and instead leaves
|
|
* reporting to invoked functions or for native PHP execution.
|
|
*
|
|
* And further this is PUBLIC DOMAIN (no copyright, no license, no warranty)
|
|
* so therefore compatible to ALL open source licenses. You could rip this
|
|
* paragraph out to republish this instead only under more restrictive terms
|
|
* or your favorite license (GNU LGPL/GPL, BSDL, MPL/CDDL, Artistic/PHPL, ..)
|
|
*
|
|
* Any contribution is appreciated. <milky*users#sf#net>
|
|
*
|
|
*/
|
|
use Piwik\SettingsServer;
|
|
|
|
/**
|
|
* ------------------------------ 5.2 ---
|
|
* @group 5_2
|
|
* @since 5.2
|
|
*
|
|
* Additions of PHP 5.2.0
|
|
* - some listed here might have appeared earlier or in release candidates
|
|
*
|
|
* @emulated
|
|
* error_get_last
|
|
* preg_last_error
|
|
* lchown
|
|
* lchgrp
|
|
* E_RECOVERABLE_ERROR
|
|
* M_SQRTPI
|
|
* M_LNPI
|
|
* M_EULER
|
|
* M_SQRT3
|
|
*
|
|
* @missing
|
|
* sys_getloadavg
|
|
* inet_ntop
|
|
* inet_pton
|
|
* array_fill_keys
|
|
* array_intersect_key
|
|
* array_intersect_ukey
|
|
* array_diff_key
|
|
* array_diff_ukey
|
|
* array_product
|
|
* pdo_drivers
|
|
* ftp_ssl_connect
|
|
* XmlReader
|
|
* XmlWriter
|
|
* PDO*
|
|
*
|
|
* @unimplementable
|
|
* stream_*
|
|
*
|
|
*/
|
|
|
|
/**
|
|
* Constants for future 64-bit integer support.
|
|
*
|
|
*/
|
|
if (!defined("PHP_INT_SIZE")) { define("PHP_INT_SIZE", 4); }
|
|
if (!defined("PHP_INT_MAX")) { define("PHP_INT_MAX", 2147483647); }
|
|
|
|
/*
|
|
These functions emulate the "character type" extension, which is
|
|
present in PHP first since version 4.3 per default. In this variant
|
|
only ASCII and Latin-1 characters are being handled. The first part
|
|
is eventually faster.
|
|
*/
|
|
|
|
|
|
/**
|
|
* Sets the default client character set.
|
|
*
|
|
* @compat
|
|
* Procedural style
|
|
* @bugs
|
|
* PHP documentation says this function exists in PHP 5 >= 5.0.5,
|
|
* but it also depends on the versions of external libraries, e.g.,
|
|
* php_mysqli.dll and libmysql.dll.
|
|
*
|
|
* @param $link mysqli MySQLi connection resource
|
|
* @param $charset string Character set
|
|
* @return bool TRUE on success, FALSE on failure
|
|
*/
|
|
if (in_array('mysqli', @get_loaded_extensions()) && !function_exists('mysqli_set_charset')) {
|
|
function mysqli_set_charset($link, $charset)
|
|
{
|
|
return mysqli_query($link, "SET NAMES '$charset'");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* parse_ini_file() replacement.
|
|
* Behaves like parse_ini_file($filename, $process_sections);
|
|
*
|
|
* @author Andrew Sohn <asohn (at) aircanopy (dot) net>
|
|
* @author anthon (dot) pang (at) gmail (dot) com
|
|
*
|
|
* @param string $filename
|
|
* @param bool $process_sections (defaults to false)
|
|
* @return array
|
|
*/
|
|
if(function_exists('parse_ini_file')) {
|
|
// provide a wrapper
|
|
function _parse_ini_file($filename, $process_sections = false) {
|
|
if(!file_exists($filename)) {
|
|
return false;
|
|
}
|
|
|
|
return parse_ini_file($filename, $process_sections);
|
|
}
|
|
} else {
|
|
// we can't redefine parse_ini_file() if it has been disabled
|
|
function _parse_ini_file($filename, $process_sections = false)
|
|
{
|
|
if(!file_exists($filename)) {
|
|
return false;
|
|
}
|
|
|
|
if(function_exists('file_get_contents')) {
|
|
$ini = file_get_contents($filename);
|
|
} else if(function_exists('file')) {
|
|
if($ini = file($filename)) {
|
|
$ini = implode("\n", $ini);
|
|
}
|
|
} else if(function_exists('fopen') && function_exists('fread')) {
|
|
$handle = fopen($filename, 'r');
|
|
if(!$handle) {
|
|
return false;
|
|
}
|
|
$ini = fread($handle, filesize($filename));
|
|
fclose($handle);
|
|
} else {
|
|
return false;
|
|
}
|
|
|
|
if($ini === false) {
|
|
return false;
|
|
}
|
|
if(is_string($ini)) { $ini = explode("\n", str_replace("\r", "\n", $ini)); }
|
|
if (count($ini) == 0) { return array(); }
|
|
|
|
$sections = array();
|
|
$values = array();
|
|
$result = array();
|
|
$globals = array();
|
|
$i = 0;
|
|
foreach ($ini as $line) {
|
|
$line = trim($line);
|
|
$line = str_replace("\t", " ", $line);
|
|
|
|
// Comments
|
|
if (!preg_match('/^[a-zA-Z0-9[]/', $line)) {continue;}
|
|
|
|
// Sections
|
|
if ($line[0] == '[') {
|
|
$tmp = explode(']', $line);
|
|
$sections[] = trim(substr($tmp[0], 1));
|
|
$i++;
|
|
continue;
|
|
}
|
|
|
|
// Key-value pair
|
|
list($key, $value) = explode('=', $line, 2);
|
|
$key = trim($key);
|
|
$value = trim($value);
|
|
if (strstr($value, ";")) {
|
|
$tmp = explode(';', $value);
|
|
if (count($tmp) == 2) {
|
|
if ((($value[0] != '"') && ($value[0] != "'")) ||
|
|
preg_match('/^".*"\s*;/', $value) || preg_match('/^".*;[^"]*$/', $value) ||
|
|
preg_match("/^'.*'\s*;/", $value) || preg_match("/^'.*;[^']*$/", $value) ){
|
|
$value = $tmp[0];
|
|
}
|
|
} else {
|
|
if ($value[0] == '"') {
|
|
$value = preg_replace('/^"(.*)".*/', '$1', $value);
|
|
} elseif ($value[0] == "'") {
|
|
$value = preg_replace("/^'(.*)'.*/", '$1', $value);
|
|
} else {
|
|
$value = $tmp[0];
|
|
}
|
|
}
|
|
}
|
|
|
|
$value = trim($value);
|
|
$value = trim($value, "'\"");
|
|
|
|
if ($i == 0) {
|
|
if (substr($key, -2) == '[]') {
|
|
$globals[substr($key, 0, -2)][] = $value;
|
|
} else {
|
|
$globals[$key] = $value;
|
|
}
|
|
} else {
|
|
if (substr($key, -2) == '[]') {
|
|
$values[$i-1][substr($key, 0, -2)][] = $value;
|
|
} else {
|
|
$values[$i-1][$key] = $value;
|
|
}
|
|
}
|
|
}
|
|
|
|
for ($j = 0; $j < $i; $j++) {
|
|
if (isset($values[$j])) {
|
|
if ($process_sections === true) {
|
|
$result[$sections[$j]] = $values[$j];
|
|
} else {
|
|
$result[] = $values[$j];
|
|
}
|
|
} else {
|
|
if ($process_sections === true) {
|
|
$result[$sections[$j]] = array();
|
|
}
|
|
}
|
|
}
|
|
|
|
return $result + $globals;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* glob() replacement.
|
|
* Behaves like glob($pattern, $flags)
|
|
*
|
|
* @author BigueNique AT yahoo DOT ca
|
|
* @author anthon (dot) pang (at) gmail (dot) com
|
|
*
|
|
* @param string $pattern
|
|
* @param int $flags GLOBL_ONLYDIR, GLOB_MARK, GLOB_NOSORT (other flags not supported; defaults to 0)
|
|
* @return array
|
|
*/
|
|
if(function_exists('glob')) {
|
|
// provide a wrapper
|
|
function _glob($pattern, $flags = 0) {
|
|
return glob($pattern, $flags);
|
|
}
|
|
} else if(function_exists('opendir') && function_exists('readdir')) {
|
|
// we can't redefine glob() if it has been disabled
|
|
function _glob($pattern, $flags = 0) {
|
|
$path = dirname($pattern);
|
|
$filePattern = basename($pattern);
|
|
if(is_dir($path) && ($handle = opendir($path)) !== false) {
|
|
$matches = array();
|
|
while(($file = readdir($handle)) !== false) {
|
|
if(($file[0] != '.')
|
|
&& fnmatch($filePattern, $file)
|
|
&& (!($flags & GLOB_ONLYDIR) || is_dir("$path/$file"))) {
|
|
$matches[] = "$path/$file" . ($flags & GLOB_MARK ? '/' : '');
|
|
}
|
|
}
|
|
closedir($handle);
|
|
if(!($flags & GLOB_NOSORT)) {
|
|
sort($matches);
|
|
}
|
|
return $matches;
|
|
}
|
|
return false;
|
|
}
|
|
} else {
|
|
function _glob($pattern, $flags = 0) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Reads entire file into a string.
|
|
* This function is not 100% compatible with the native function.
|
|
*
|
|
* @see http://php.net/file_get_contents
|
|
* @since PHP 4.3.0
|
|
*
|
|
* @param string $filename Name of the file to read.
|
|
* @return string The read data or false on failure.
|
|
*/
|
|
if (!function_exists('file_get_contents'))
|
|
{
|
|
function file_get_contents($filename)
|
|
{
|
|
$fhandle = fopen($filename, "r");
|
|
$fcontents = fread($fhandle, filesize($filename));
|
|
fclose($fhandle);
|
|
return $fcontents;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Safe serialize() and unserialize() replacements
|
|
*
|
|
* @license Public Domain
|
|
*
|
|
* @author anthon (dot) pang (at) gmail (dot) com
|
|
*/
|
|
|
|
/*
|
|
* Arbitrary limits for safe_unserialize()
|
|
*/
|
|
define('MAX_SERIALIZED_INPUT_LENGTH', 4096);
|
|
define('MAX_SERIALIZED_ARRAY_LENGTH', 256);
|
|
define('MAX_SERIALIZED_ARRAY_DEPTH', 3);
|
|
|
|
|
|
/**
|
|
* Safe serialize() replacement
|
|
* - output a strict subset of PHP's native serialized representation
|
|
* - does not serialize objects
|
|
*
|
|
* @param mixed $value
|
|
* @return string
|
|
* @throw Exception if $value is malformed or contains unsupported types (e.g., resources, objects)
|
|
*/
|
|
function _safe_serialize( $value )
|
|
{
|
|
if(is_null($value))
|
|
{
|
|
return 'N;';
|
|
}
|
|
if(is_bool($value))
|
|
{
|
|
return 'b:'.(int)$value.';';
|
|
}
|
|
if(is_int($value))
|
|
{
|
|
return 'i:'.$value.';';
|
|
}
|
|
if(is_float($value))
|
|
{
|
|
return 'd:'.str_replace(',', '.', $value).';';
|
|
}
|
|
if(is_string($value))
|
|
{
|
|
return 's:'.strlen($value).':"'.$value.'";';
|
|
}
|
|
if(is_array($value))
|
|
{
|
|
$out = '';
|
|
foreach($value as $k => $v)
|
|
{
|
|
$out .= _safe_serialize($k) . _safe_serialize($v);
|
|
}
|
|
|
|
return 'a:'.count($value).':{'.$out.'}';
|
|
}
|
|
|
|
// safe_serialize cannot serialize resources or objects
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Wrapper for _safe_serialize() that handles exceptions and multibyte encoding issue
|
|
*
|
|
* @param mixed $value
|
|
* @return string
|
|
*/
|
|
function safe_serialize( $value )
|
|
{
|
|
// ensure we use the byte count for strings even when strlen() is overloaded by mb_strlen()
|
|
if (function_exists('mb_internal_encoding') &&
|
|
(((int) ini_get('mbstring.func_overload')) & 2))
|
|
{
|
|
$mbIntEnc = mb_internal_encoding();
|
|
mb_internal_encoding('ASCII');
|
|
}
|
|
|
|
$out = _safe_serialize($value);
|
|
|
|
if (isset($mbIntEnc))
|
|
{
|
|
mb_internal_encoding($mbIntEnc);
|
|
}
|
|
return $out;
|
|
}
|
|
|
|
/**
|
|
* Safe unserialize() replacement
|
|
* - accepts a strict subset of PHP's native serialized representation
|
|
* - does not unserialize objects
|
|
*
|
|
* @param string $str
|
|
* @return mixed
|
|
* @throw Exception if $str is malformed or contains unsupported types (e.g., resources, objects)
|
|
*/
|
|
function _safe_unserialize($str)
|
|
{
|
|
if(strlen($str) > MAX_SERIALIZED_INPUT_LENGTH)
|
|
{
|
|
// input exceeds MAX_SERIALIZED_INPUT_LENGTH
|
|
return false;
|
|
}
|
|
|
|
if(empty($str) || !is_string($str))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
$stack = array();
|
|
$expected = array();
|
|
|
|
/*
|
|
* states:
|
|
* 0 - initial state, expecting a single value or array
|
|
* 1 - terminal state
|
|
* 2 - in array, expecting end of array or a key
|
|
* 3 - in array, expecting value or another array
|
|
*/
|
|
$state = 0;
|
|
while($state != 1)
|
|
{
|
|
$type = isset($str[0]) ? $str[0] : '';
|
|
|
|
if($type == '}')
|
|
{
|
|
$str = substr($str, 1);
|
|
}
|
|
else if($type == 'N' && $str[1] == ';')
|
|
{
|
|
$value = null;
|
|
$str = substr($str, 2);
|
|
}
|
|
else if($type == 'b' && preg_match('/^b:([01]);/', $str, $matches))
|
|
{
|
|
$value = $matches[1] == '1' ? true : false;
|
|
$str = substr($str, 4);
|
|
}
|
|
else if($type == 'i' && preg_match('/^i:(-?[0-9]+);(.*)/s', $str, $matches))
|
|
{
|
|
$value = (int)$matches[1];
|
|
$str = $matches[2];
|
|
}
|
|
else if($type == 'd' && preg_match('/^d:(-?[0-9]+\.?[0-9]*(E[+-][0-9]+)?);(.*)/s', $str, $matches))
|
|
{
|
|
$value = (float)$matches[1];
|
|
$str = $matches[3];
|
|
}
|
|
else if($type == 's' && preg_match('/^s:([0-9]+):"(.*)/s', $str, $matches) && substr($matches[2], (int)$matches[1], 2) == '";')
|
|
{
|
|
$value = substr($matches[2], 0, (int)$matches[1]);
|
|
$str = substr($matches[2], (int)$matches[1] + 2);
|
|
}
|
|
else if($type == 'a' && preg_match('/^a:([0-9]+):{(.*)/s', $str, $matches) && $matches[1] < MAX_SERIALIZED_ARRAY_LENGTH)
|
|
{
|
|
$expectedLength = (int)$matches[1];
|
|
$str = $matches[2];
|
|
}
|
|
else
|
|
{
|
|
// object or unknown/malformed type
|
|
return false;
|
|
}
|
|
|
|
switch($state)
|
|
{
|
|
case 3: // in array, expecting value or another array
|
|
if($type == 'a')
|
|
{
|
|
if(count($stack) >= MAX_SERIALIZED_ARRAY_DEPTH)
|
|
{
|
|
// array nesting exceeds MAX_SERIALIZED_ARRAY_DEPTH
|
|
return false;
|
|
}
|
|
|
|
$stack[] = &$list;
|
|
$list[$key] = array();
|
|
$list = &$list[$key];
|
|
$expected[] = $expectedLength;
|
|
$state = 2;
|
|
break;
|
|
}
|
|
if($type != '}')
|
|
{
|
|
$list[$key] = $value;
|
|
$state = 2;
|
|
break;
|
|
}
|
|
|
|
// missing array value
|
|
return false;
|
|
|
|
case 2: // in array, expecting end of array or a key
|
|
if($type == '}')
|
|
{
|
|
if(count($list) < end($expected))
|
|
{
|
|
// array size less than expected
|
|
return false;
|
|
}
|
|
|
|
unset($list);
|
|
$list = &$stack[count($stack)-1];
|
|
array_pop($stack);
|
|
|
|
// go to terminal state if we're at the end of the root array
|
|
array_pop($expected);
|
|
if(count($expected) == 0) {
|
|
$state = 1;
|
|
}
|
|
break;
|
|
}
|
|
if($type == 'i' || $type == 's')
|
|
{
|
|
if(count($list) >= MAX_SERIALIZED_ARRAY_LENGTH)
|
|
{
|
|
// array size exceeds MAX_SERIALIZED_ARRAY_LENGTH
|
|
return false;
|
|
}
|
|
if(count($list) >= end($expected))
|
|
{
|
|
// array size exceeds expected length
|
|
return false;
|
|
}
|
|
|
|
$key = $value;
|
|
$state = 3;
|
|
break;
|
|
}
|
|
|
|
// illegal array index type
|
|
return false;
|
|
|
|
case 0: // expecting array or value
|
|
if($type == 'a')
|
|
{
|
|
if(count($stack) >= MAX_SERIALIZED_ARRAY_DEPTH)
|
|
{
|
|
// array nesting exceeds MAX_SERIALIZED_ARRAY_DEPTH
|
|
return false;
|
|
}
|
|
|
|
$data = array();
|
|
$list = &$data;
|
|
$expected[] = $expectedLength;
|
|
$state = 2;
|
|
break;
|
|
}
|
|
if($type != '}')
|
|
{
|
|
$data = $value;
|
|
$state = 1;
|
|
break;
|
|
}
|
|
|
|
// not in array
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if(!empty($str))
|
|
{
|
|
// trailing data in input
|
|
return false;
|
|
}
|
|
return $data;
|
|
}
|
|
|
|
/**
|
|
* Wrapper for _safe_unserialize() that handles exceptions and multibyte encoding issue
|
|
*
|
|
* @param string $str
|
|
* @return mixed
|
|
*/
|
|
function safe_unserialize( $str )
|
|
{
|
|
// ensure we use the byte count for strings even when strlen() is overloaded by mb_strlen()
|
|
if (function_exists('mb_internal_encoding') &&
|
|
(((int) ini_get('mbstring.func_overload')) & 2))
|
|
{
|
|
$mbIntEnc = mb_internal_encoding();
|
|
mb_internal_encoding('ASCII');
|
|
}
|
|
|
|
$out = _safe_unserialize($str);
|
|
|
|
if (isset($mbIntEnc))
|
|
{
|
|
mb_internal_encoding($mbIntEnc);
|
|
}
|
|
return $out;
|
|
}
|
|
|
|
/**
|
|
* readfile() replacement.
|
|
* Behaves similar to readfile($filename);
|
|
*
|
|
* @author anthon (dot) pang (at) gmail (dot) com
|
|
*
|
|
* @param string $filename
|
|
* @param bool $useIncludePath
|
|
* @param resource $context
|
|
* @return int the number of bytes read from the file, or false if an error occurs
|
|
*/
|
|
function _readfile($filename, $byteStart, $byteEnd, $useIncludePath = false, $context = null)
|
|
{
|
|
$count = @filesize($filename);
|
|
|
|
// built-in function has a 2 MB limit when using mmap
|
|
if (function_exists('readfile')
|
|
&& $count <= (2 * 1024 * 1024)
|
|
&& $byteStart == 0
|
|
&& $byteEnd == $count
|
|
) {
|
|
return @readfile($filename, $useIncludePath, $context);
|
|
}
|
|
|
|
// when in doubt (or when readfile() function is disabled)
|
|
$handle = @fopen($filename, SettingsServer::isWindows() ? "rb" : "r");
|
|
if ($handle) {
|
|
fseek($handle, $byteStart);
|
|
|
|
for ($pos = $byteStart; $pos < $byteEnd && !feof($handle); $pos = ftell($handle)) {
|
|
echo fread($handle, min(8192, $byteEnd - $pos));
|
|
|
|
@ob_flush();
|
|
@flush();
|
|
}
|
|
|
|
fclose($handle);
|
|
return $byteEnd - $byteStart;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* utf8_encode replacement
|
|
*
|
|
* @param string $data
|
|
* @return string
|
|
*/
|
|
if (!function_exists('utf8_encode')) {
|
|
function utf8_encode($data) {
|
|
if (function_exists('iconv')) {
|
|
return @iconv('ISO-8859-1', 'UTF-8', $data);
|
|
}
|
|
return $data;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* utf8_decode replacement
|
|
*
|
|
* @param string $data
|
|
* @return string
|
|
*/
|
|
if (!function_exists('utf8_decode')) {
|
|
function utf8_decode($data) {
|
|
if (function_exists('iconv')) {
|
|
return @iconv('UTF-8', 'ISO-8859-1', $data);
|
|
}
|
|
return $data;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* On ubuntu in some cases, there is a bug that gzopen does not exist and one must use gzopen64 instead
|
|
*/
|
|
if (!function_exists('gzopen')
|
|
&& function_exists('gzopen64')) {
|
|
function gzopen($filename , $mode = 'r', $use_include_path = 0 )
|
|
{
|
|
return gzopen64($filename , $mode, $use_include_path);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Need to catch that PHP7 error object on php5
|
|
*/
|
|
if( !class_exists('\Error')) {
|
|
class Error {
|
|
|
|
}
|
|
}
|
|
|
|
if(!function_exists('fnmatch')) {
|
|
|
|
function fnmatch($pattern, $string) {
|
|
return preg_match("#^".strtr(preg_quote($pattern, '#'), array('\*' => '.*', '\?' => '.'))."$#i", $string);
|
|
} // end
|
|
|
|
} // end if
|