Current oav website
This commit is contained in:
43
dotclear._no/inc/libs/clearbricks/common/_main.php
Normal file
43
dotclear._no/inc/libs/clearbricks/common/_main.php
Normal file
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Clearbricks
|
||||
* @subpackage Common
|
||||
*
|
||||
* @copyright Olivier Meunier & Association Dotclear
|
||||
* @copyright GPL-2.0-only
|
||||
*/
|
||||
|
||||
define('CLEARBRICKS_VERSION', '1.1');
|
||||
|
||||
# Autoload
|
||||
$__autoload = [
|
||||
'crypt' => dirname(__FILE__) . '/lib.crypt.php',
|
||||
'dt' => dirname(__FILE__) . '/lib.date.php',
|
||||
'files' => dirname(__FILE__) . '/lib.files.php',
|
||||
'path' => dirname(__FILE__) . '/lib.files.php',
|
||||
'form' => dirname(__FILE__) . '/lib.form.php',
|
||||
'formSelectOption' => dirname(__FILE__) . '/lib.form.php',
|
||||
'html' => dirname(__FILE__) . '/lib.html.php',
|
||||
'http' => dirname(__FILE__) . '/lib.http.php',
|
||||
'text' => dirname(__FILE__) . '/lib.text.php'
|
||||
];
|
||||
|
||||
# autoload for clearbricks
|
||||
function cb_autoload($name)
|
||||
{
|
||||
global $__autoload;
|
||||
|
||||
if (isset($__autoload[$name])) {
|
||||
require_once $__autoload[$name];
|
||||
}
|
||||
}
|
||||
spl_autoload_register("cb_autoload");
|
||||
|
||||
# We only need l10n __() function
|
||||
require_once dirname(__FILE__) . '/lib.l10n.php';
|
||||
|
||||
# We set default timezone to avoid warning
|
||||
dt::setTZ('UTC');
|
||||
|
||||
# JSON functions for PHP < 5.2 or PHP > 5.2 compiling without json
|
||||
require_once dirname(__FILE__) . '/lib.json.php';
|
||||
79
dotclear._no/inc/libs/clearbricks/common/lib.crypt.php
Normal file
79
dotclear._no/inc/libs/clearbricks/common/lib.crypt.php
Normal file
@ -0,0 +1,79 @@
|
||||
<?php
|
||||
/**
|
||||
* @class crypt
|
||||
* @brief Functions to handle passwords or sensitive data
|
||||
*
|
||||
* @package Clearbricks
|
||||
* @subpackage Common
|
||||
*
|
||||
* @copyright Olivier Meunier & Association Dotclear
|
||||
* @copyright GPL-2.0-only
|
||||
*/
|
||||
|
||||
class crypt
|
||||
{
|
||||
/**
|
||||
* SHA1 or MD5 + HMAC
|
||||
*
|
||||
* Returns an HMAC encoded value of <var>$data</var>, using the said <var>$key</var>
|
||||
* and <var>$hashfunc</var> as hash method (sha1 or md5 are accepted if hash_hmac function not exists.)
|
||||
*
|
||||
* @param string $key Hash key
|
||||
* @param string $data Data
|
||||
* @param string $hashfunc Hash function (md5 or sha1)
|
||||
* @return string
|
||||
*/
|
||||
public static function hmac($key, $data, $hashfunc = 'sha1')
|
||||
{
|
||||
|
||||
if (function_exists('hash_hmac')) {
|
||||
if (!in_array($hashfunc, hash_algos())) {
|
||||
$hashfunc = 'sha1';
|
||||
}
|
||||
return hash_hmac($hashfunc, $data, $key);
|
||||
}
|
||||
|
||||
return self::hmac_legacy($key, $data, $hashfunc);
|
||||
}
|
||||
|
||||
public static function hmac_legacy($key, $data, $hashfunc = 'sha1')
|
||||
{
|
||||
// Legacy way
|
||||
if ($hashfunc != 'sha1') {
|
||||
$hashfunc = 'md5';
|
||||
}
|
||||
$blocksize = 64;
|
||||
if (strlen($key) > $blocksize) {
|
||||
$key = pack('H*', $hashfunc($key));
|
||||
}
|
||||
$key = str_pad($key, $blocksize, chr(0x00));
|
||||
$ipad = str_repeat(chr(0x36), $blocksize);
|
||||
$opad = str_repeat(chr(0x5c), $blocksize);
|
||||
$hmac = pack('H*', $hashfunc(($key ^ $opad) . pack('H*', $hashfunc(($key ^ $ipad) . $data))));
|
||||
return bin2hex($hmac);
|
||||
}
|
||||
|
||||
/**
|
||||
* Password generator
|
||||
*
|
||||
* Returns an n characters random password.
|
||||
*
|
||||
* @param integer $length required length
|
||||
* @return string
|
||||
*/
|
||||
public static function createPassword($length = 8)
|
||||
{
|
||||
$pwd = [];
|
||||
$chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
|
||||
$chars2 = '$!@';
|
||||
|
||||
for ($i = 0; $i < $length; $i++) {
|
||||
$pwd[] = $chars[rand(0, strlen($chars) - 1)];
|
||||
}
|
||||
for ($j = 0; $j < (int)($length / 4); $j++) {
|
||||
$pos = rand(0, 3) + 4 * $j;
|
||||
$pwd[$pos] = $chars2[rand(0, strlen($chars2) - 1)];
|
||||
}
|
||||
return implode('', $pwd);
|
||||
}
|
||||
}
|
||||
288
dotclear._no/inc/libs/clearbricks/common/lib.date.php
Normal file
288
dotclear._no/inc/libs/clearbricks/common/lib.date.php
Normal file
@ -0,0 +1,288 @@
|
||||
<?php
|
||||
/**
|
||||
* @class dt
|
||||
* @brief Date/time utilities
|
||||
*
|
||||
* @package Clearbricks
|
||||
* @subpackage Common
|
||||
*
|
||||
* @copyright Olivier Meunier & Association Dotclear
|
||||
* @copyright GPL-2.0-only
|
||||
*/
|
||||
|
||||
class dt
|
||||
{
|
||||
private static $timezones = null;
|
||||
|
||||
/**
|
||||
* Timestamp formating
|
||||
*
|
||||
* Returns a date formated like PHP <a href="http://www.php.net/manual/en/function.strftime.php">strftime</a>
|
||||
* function.
|
||||
* Special cases %a, %A, %b and %B are handled by {@link l10n} library.
|
||||
*
|
||||
* @param string $p Format pattern
|
||||
* @param integer $ts Timestamp
|
||||
* @param string $tz Timezone
|
||||
* @return string
|
||||
*/
|
||||
public static function str($p, $ts = null, $tz = null)
|
||||
{
|
||||
if ($ts === null) {$ts = time();}
|
||||
|
||||
$hash = '799b4e471dc78154865706469d23d512';
|
||||
$p = preg_replace('/(?<!%)%(a|A)/', '{{' . $hash . '__$1%w__}}', $p);
|
||||
$p = preg_replace('/(?<!%)%(b|B)/', '{{' . $hash . '__$1%m__}}', $p);
|
||||
|
||||
if ($tz) {
|
||||
$T = self::getTZ();
|
||||
self::setTZ($tz);
|
||||
}
|
||||
|
||||
$res = strftime($p, $ts);
|
||||
|
||||
if ($tz) {
|
||||
self::setTZ($T);
|
||||
}
|
||||
|
||||
$res = preg_replace_callback('/{{' . $hash . '__(a|A|b|B)([0-9]{1,2})__}}/', ['self', '_callback'], $res);
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Date to date
|
||||
*
|
||||
* Format a literal date to another literal date.
|
||||
*
|
||||
* @param string $p Format pattern
|
||||
* @param string $dt Date
|
||||
* @param string $tz Timezone
|
||||
* @return string
|
||||
*/
|
||||
public static function dt2str($p, $dt, $tz = null)
|
||||
{
|
||||
return dt::str($p, strtotime($dt), $tz);
|
||||
}
|
||||
|
||||
/**
|
||||
* ISO-8601 formatting
|
||||
*
|
||||
* Returns a timestamp converted to ISO-8601 format.
|
||||
*
|
||||
* @param integer $ts Timestamp
|
||||
* @param string $tz Timezone
|
||||
* @return string
|
||||
*/
|
||||
public static function iso8601($ts, $tz = 'UTC')
|
||||
{
|
||||
$o = self::getTimeOffset($tz, $ts);
|
||||
$of = sprintf('%02u:%02u', abs($o) / 3600, (abs($o) % 3600) / 60);
|
||||
return date('Y-m-d\\TH:i:s', $ts) . ($o < 0 ? '-' : '+') . $of;
|
||||
}
|
||||
|
||||
/**
|
||||
* RFC-822 formatting
|
||||
*
|
||||
* Returns a timestamp converted to RFC-822 format.
|
||||
*
|
||||
* @param integer $ts Timestamp
|
||||
* @param string $tz Timezone
|
||||
* @return string
|
||||
*/
|
||||
public static function rfc822($ts, $tz = 'UTC')
|
||||
{
|
||||
# Get offset
|
||||
$o = self::getTimeOffset($tz, $ts);
|
||||
$of = sprintf('%02u%02u', abs($o) / 3600, (abs($o) % 3600) / 60);
|
||||
return strftime('%a, %d %b %Y %H:%M:%S ' . ($o < 0 ? '-' : '+') . $of, $ts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Timezone set
|
||||
*
|
||||
* Set timezone during script execution.
|
||||
*
|
||||
* @param string $tz Timezone
|
||||
*/
|
||||
public static function setTZ($tz)
|
||||
{
|
||||
if (function_exists('date_default_timezone_set')) {
|
||||
date_default_timezone_set($tz);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ini_get('safe_mode')) {
|
||||
putenv('TZ=' . $tz);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Current timezone
|
||||
*
|
||||
* Returns current timezone.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getTZ()
|
||||
{
|
||||
if (function_exists('date_default_timezone_get')) {
|
||||
return date_default_timezone_get();
|
||||
}
|
||||
|
||||
return date('T');
|
||||
}
|
||||
|
||||
/**
|
||||
* Time offset
|
||||
*
|
||||
* Get time offset for a timezone and an optionnal $ts timestamp.
|
||||
*
|
||||
* @param string $tz Timezone
|
||||
* @param integer $ts Timestamp
|
||||
* @return integer
|
||||
*/
|
||||
public static function getTimeOffset($tz, $ts = false)
|
||||
{
|
||||
if (!$ts) {
|
||||
$ts = time();
|
||||
}
|
||||
|
||||
$server_tz = self::getTZ();
|
||||
$server_offset = date('Z', $ts);
|
||||
|
||||
self::setTZ($tz);
|
||||
$cur_offset = date('Z', $ts);
|
||||
|
||||
self::setTZ($server_tz);
|
||||
|
||||
return $cur_offset - $server_offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* UTC conversion
|
||||
*
|
||||
* Returns any timestamp from current timezone to UTC timestamp.
|
||||
*
|
||||
* @param integer $ts Timestamp
|
||||
* @return integer
|
||||
*/
|
||||
public static function toUTC($ts)
|
||||
{
|
||||
return $ts + self::getTimeOffset('UTC', $ts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add timezone
|
||||
*
|
||||
* Returns a timestamp with its timezone offset.
|
||||
*
|
||||
* @param string $tz Timezone
|
||||
* @param integer $ts Timestamp
|
||||
* @return integer
|
||||
*/
|
||||
public static function addTimeZone($tz, $ts = false)
|
||||
{
|
||||
if ($ts === false) {
|
||||
$ts = time();
|
||||
}
|
||||
return $ts + self::getTimeOffset($tz, $ts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Timzones
|
||||
*
|
||||
* Returns an array of supported timezones, codes are keys and names are values.
|
||||
*
|
||||
* @param boolean $flip Names are keys and codes are values
|
||||
* @param boolean $groups Return timezones in arrays of continents
|
||||
* @return array
|
||||
*/
|
||||
public static function getZones($flip = false, $groups = false)
|
||||
{
|
||||
if (is_null(self::$timezones)) {
|
||||
// Read timezones from file
|
||||
if (!is_readable($f = dirname(__FILE__) . '/tz.dat')) {
|
||||
return [];
|
||||
}
|
||||
$tz = file(dirname(__FILE__) . '/tz.dat');
|
||||
$res = [];
|
||||
foreach ($tz as $v) {
|
||||
$v = trim($v);
|
||||
if ($v) {
|
||||
$res[$v] = str_replace('_', ' ', $v);
|
||||
}
|
||||
}
|
||||
// Store timezones for further accesses
|
||||
self::$timezones = $res;
|
||||
} else {
|
||||
// Timezones already read from file
|
||||
$res = self::$timezones;
|
||||
}
|
||||
|
||||
if ($flip) {
|
||||
$res = array_flip($res);
|
||||
if ($groups) {
|
||||
$tmp = [];
|
||||
foreach ($res as $k => $v) {
|
||||
$g = explode('/', $k);
|
||||
$tmp[$g[0]][$k] = $v;
|
||||
}
|
||||
$res = $tmp;
|
||||
}
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
private static function _callback($args)
|
||||
{
|
||||
$b = [
|
||||
1 => '_Jan',
|
||||
2 => '_Feb',
|
||||
3 => '_Mar',
|
||||
4 => '_Apr',
|
||||
5 => '_May',
|
||||
6 => '_Jun',
|
||||
7 => '_Jul',
|
||||
8 => '_Aug',
|
||||
9 => '_Sep',
|
||||
10 => '_Oct',
|
||||
11 => '_Nov',
|
||||
12 => '_Dec'];
|
||||
|
||||
$B = [
|
||||
1 => 'January',
|
||||
2 => 'February',
|
||||
3 => 'March',
|
||||
4 => 'April',
|
||||
5 => 'May',
|
||||
6 => 'June',
|
||||
7 => 'July',
|
||||
8 => 'August',
|
||||
9 => 'September',
|
||||
10 => 'October',
|
||||
11 => 'November',
|
||||
12 => 'December'];
|
||||
|
||||
$a = [
|
||||
1 => '_Mon',
|
||||
2 => '_Tue',
|
||||
3 => '_Wed',
|
||||
4 => '_Thu',
|
||||
5 => '_Fri',
|
||||
6 => '_Sat',
|
||||
0 => '_Sun'];
|
||||
|
||||
$A = [
|
||||
1 => 'Monday',
|
||||
2 => 'Tuesday',
|
||||
3 => 'Wednesday',
|
||||
4 => 'Thursday',
|
||||
5 => 'Friday',
|
||||
6 => 'Saturday',
|
||||
0 => 'Sunday'];
|
||||
|
||||
return __(${$args[1]}[(integer) $args[2]]);
|
||||
}
|
||||
}
|
||||
640
dotclear._no/inc/libs/clearbricks/common/lib.files.php
Normal file
640
dotclear._no/inc/libs/clearbricks/common/lib.files.php
Normal file
@ -0,0 +1,640 @@
|
||||
<?php
|
||||
/**
|
||||
* @class files
|
||||
* @brief Files manipulation utilities
|
||||
*
|
||||
* @package Clearbricks
|
||||
* @subpackage Common
|
||||
*
|
||||
* @copyright Olivier Meunier & Association Dotclear
|
||||
* @copyright GPL-2.0-only
|
||||
*/
|
||||
|
||||
class files
|
||||
{
|
||||
public static $dir_mode = null; ///< Default directories mode
|
||||
|
||||
public static $mimeType = ///< MIME types
|
||||
[
|
||||
'odt' => 'application/vnd.oasis.opendocument.text',
|
||||
'odp' => 'application/vnd.oasis.opendocument.presentation',
|
||||
'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
|
||||
|
||||
'sxw' => 'application/vnd.sun.xml.writer',
|
||||
'sxc' => 'application/vnd.sun.xml.calc',
|
||||
'sxi' => 'application/vnd.sun.xml.impress',
|
||||
|
||||
'ppt' => 'application/mspowerpoint',
|
||||
'doc' => 'application/msword',
|
||||
'xls' => 'application/msexcel',
|
||||
'rtf' => 'application/rtf',
|
||||
|
||||
'pdf' => 'application/pdf',
|
||||
'ps' => 'application/postscript',
|
||||
'ai' => 'application/postscript',
|
||||
'eps' => 'application/postscript',
|
||||
'json' => 'application/json',
|
||||
'xml' => 'application/xml',
|
||||
|
||||
'bin' => 'application/octet-stream',
|
||||
'exe' => 'application/octet-stream',
|
||||
|
||||
'bz2' => 'application/x-bzip',
|
||||
'deb' => 'application/x-debian-package',
|
||||
'gz' => 'application/x-gzip',
|
||||
'jar' => 'application/x-java-archive',
|
||||
'rar' => 'application/rar',
|
||||
'rpm' => 'application/x-redhat-package-manager',
|
||||
'tar' => 'application/x-tar',
|
||||
'tgz' => 'application/x-gtar',
|
||||
'zip' => 'application/zip',
|
||||
|
||||
'aiff' => 'audio/x-aiff',
|
||||
'ua' => 'audio/basic',
|
||||
'mp3' => 'audio/mpeg3',
|
||||
'mid' => 'audio/x-midi',
|
||||
'midi' => 'audio/x-midi',
|
||||
'ogg' => 'application/ogg',
|
||||
'ra' => 'audio/x-pn-realaudio',
|
||||
'ram' => 'audio/x-pn-realaudio',
|
||||
'wav' => 'audio/x-wav',
|
||||
'wma' => 'audio/x-ms-wma',
|
||||
|
||||
'swf' => 'application/x-shockwave-flash',
|
||||
'swfl' => 'application/x-shockwave-flash',
|
||||
'js' => 'application/javascript',
|
||||
|
||||
'bmp' => 'image/bmp',
|
||||
'gif' => 'image/gif',
|
||||
'ico' => 'image/vnd.microsoft.icon',
|
||||
'jpeg' => 'image/jpeg',
|
||||
'jpg' => 'image/jpeg',
|
||||
'jpe' => 'image/jpeg',
|
||||
'png' => 'image/png',
|
||||
'svg' => 'image/svg+xml',
|
||||
'tiff' => 'image/tiff',
|
||||
'tif' => 'image/tiff',
|
||||
'webp' => 'image/webp',
|
||||
'xbm' => 'image/x-xbitmap',
|
||||
|
||||
'css' => 'text/css',
|
||||
'csv' => 'text/csv',
|
||||
'html' => 'text/html',
|
||||
'htm' => 'text/html',
|
||||
'txt' => 'text/plain',
|
||||
'rtf' => 'text/richtext',
|
||||
'rtx' => 'text/richtext',
|
||||
|
||||
'mpg' => 'video/mpeg',
|
||||
'mpeg' => 'video/mpeg',
|
||||
'mpe' => 'video/mpeg',
|
||||
'ogv' => 'video/ogg',
|
||||
'viv' => 'video/vnd.vivo',
|
||||
'vivo' => 'video/vnd.vivo',
|
||||
'qt' => 'video/quicktime',
|
||||
'mov' => 'video/quicktime',
|
||||
'mp4' => 'video/mp4',
|
||||
'm4v' => 'video/x-m4v',
|
||||
'flv' => 'video/x-flv',
|
||||
'avi' => 'video/x-msvideo',
|
||||
'wmv' => 'video/x-ms-wmv'
|
||||
];
|
||||
|
||||
/**
|
||||
* Directory scanning
|
||||
*
|
||||
* Returns a directory child files and directories.
|
||||
*
|
||||
* @param string $d Path to scan
|
||||
* @param boolean $order Order results
|
||||
* @return array
|
||||
*/
|
||||
public static function scandir($d, $order = true)
|
||||
{
|
||||
$res = [];
|
||||
$dh = @opendir($d);
|
||||
|
||||
if ($dh === false) {
|
||||
throw new Exception(__('Unable to open directory.'));
|
||||
}
|
||||
|
||||
while (($f = readdir($dh)) !== false) {
|
||||
$res[] = $f;
|
||||
}
|
||||
closedir($dh);
|
||||
|
||||
if ($order) {
|
||||
sort($res);
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* File extension
|
||||
*
|
||||
* Returns a file extension.
|
||||
*
|
||||
* @param string $f File name
|
||||
* @return string
|
||||
*/
|
||||
public static function getExtension($f)
|
||||
{
|
||||
if (function_exists('pathinfo')) {
|
||||
return strtolower(pathinfo($f, PATHINFO_EXTENSION));
|
||||
} else {
|
||||
$f = explode('.', basename($f));
|
||||
if (count($f) <= 1) {return '';}
|
||||
return strtolower($f[count($f) - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* MIME type
|
||||
*
|
||||
* Returns a file MIME type, based on static var {@link $mimeType}
|
||||
*
|
||||
* @param string $f File name
|
||||
* @return string
|
||||
*/
|
||||
public static function getMimeType($f)
|
||||
{
|
||||
$ext = self::getExtension($f);
|
||||
$types = self::mimeTypes();
|
||||
|
||||
if (isset($types[$ext])) {
|
||||
return $types[$ext];
|
||||
} else {
|
||||
return 'application/octet-stream';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* MIME types
|
||||
*
|
||||
* Returns all defined MIME types.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function mimeTypes()
|
||||
{
|
||||
return self::$mimeType;
|
||||
}
|
||||
|
||||
/**
|
||||
* New MIME types
|
||||
*
|
||||
* Append new MIME types to defined MIME types.
|
||||
*
|
||||
* @param array $tab New MIME types.
|
||||
*/
|
||||
public static function registerMimeTypes($tab)
|
||||
{
|
||||
self::$mimeType = array_merge(self::$mimeType, $tab);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is a file or directory deletable.
|
||||
*
|
||||
* Returns true if $f is a file or directory and is deletable.
|
||||
*
|
||||
* @param string $f File or directory
|
||||
* @return boolean
|
||||
*/
|
||||
public static function isDeletable($f)
|
||||
{
|
||||
if (is_file($f)) {
|
||||
return is_writable(dirname($f));
|
||||
} elseif (is_dir($f)) {
|
||||
return (is_writable(dirname($f)) && count(files::scandir($f)) <= 2);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursive removal
|
||||
*
|
||||
* Remove recursively a directory.
|
||||
*
|
||||
* @param string $dir Directory patch
|
||||
* @return boolean
|
||||
*/
|
||||
public static function deltree($dir)
|
||||
{
|
||||
$current_dir = opendir($dir);
|
||||
while ($entryname = readdir($current_dir)) {
|
||||
if (is_dir($dir . '/' . $entryname) and ($entryname != '.' and $entryname != '..')) {
|
||||
if (!files::deltree($dir . '/' . $entryname)) {
|
||||
return false;
|
||||
}
|
||||
} elseif ($entryname != '.' and $entryname != '..') {
|
||||
if (!@unlink($dir . '/' . $entryname)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir($current_dir);
|
||||
return @rmdir($dir);
|
||||
}
|
||||
|
||||
/**
|
||||
* Touch file
|
||||
*
|
||||
* Set file modification time to now.
|
||||
*
|
||||
* @param string $f File to change
|
||||
*/
|
||||
public static function touch($f)
|
||||
{
|
||||
if (is_writable($f)) {
|
||||
if (function_exists('touch')) {
|
||||
@touch($f);
|
||||
} else {
|
||||
# Very bad hack
|
||||
@file_put_contents($f, file_get_contents($f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Directory creation.
|
||||
*
|
||||
* Creates directory $f. If $r is true, attempts to create needed parents
|
||||
* directories.
|
||||
*
|
||||
* @param string $f Directory to create
|
||||
* @param boolean $r Create parent directories
|
||||
*/
|
||||
public static function makeDir($f, $r = false)
|
||||
{
|
||||
if (empty($f)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (DIRECTORY_SEPARATOR == '\\') {
|
||||
$f = str_replace('/', '\\', $f);
|
||||
}
|
||||
|
||||
if (is_dir($f)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($r) {
|
||||
$dir = path::real($f, false);
|
||||
$dirs = [];
|
||||
|
||||
while (!is_dir($dir)) {
|
||||
array_unshift($dirs, basename($dir));
|
||||
$dir = dirname($dir);
|
||||
}
|
||||
|
||||
foreach ($dirs as $d) {
|
||||
$dir .= DIRECTORY_SEPARATOR . $d;
|
||||
if ($d != '' && !is_dir($dir)) {
|
||||
self::makeDir($dir);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (@mkdir($f) === false) {
|
||||
throw new Exception(__('Unable to create directory.'));
|
||||
}
|
||||
self::inheritChmod($f);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mode inheritage
|
||||
*
|
||||
* Sets file or directory mode according to its parent.
|
||||
*
|
||||
* @param string $file File to change
|
||||
*/
|
||||
public static function inheritChmod($file)
|
||||
{
|
||||
if (!function_exists('fileperms') || !function_exists('chmod')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (self::$dir_mode != null) {
|
||||
return @chmod($file, self::$dir_mode);
|
||||
} else {
|
||||
return @chmod($file, fileperms(dirname($file)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes file content.
|
||||
*
|
||||
* Writes $f_content into $f file.
|
||||
*
|
||||
* @param string $f File to edit
|
||||
* @param string $f_content Content to write
|
||||
*/
|
||||
public static function putContent($f, $f_content)
|
||||
{
|
||||
if (file_exists($f) && !is_writable($f)) {
|
||||
throw new Exception(__('File is not writable.'));
|
||||
}
|
||||
|
||||
$fp = @fopen($f, 'w');
|
||||
|
||||
if ($fp === false) {
|
||||
throw new Exception(__('Unable to open file.'));
|
||||
}
|
||||
|
||||
fwrite($fp, $f_content, strlen($f_content));
|
||||
fclose($fp);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Human readable file size.
|
||||
*
|
||||
* @param integer $size Bytes
|
||||
* @return string
|
||||
*/
|
||||
public static function size($size)
|
||||
{
|
||||
$kb = 1024;
|
||||
$mb = 1024 * $kb;
|
||||
$gb = 1024 * $mb;
|
||||
$tb = 1024 * $gb;
|
||||
|
||||
if ($size < $kb) {
|
||||
return $size . " B";
|
||||
} else if ($size < $mb) {
|
||||
return round($size / $kb, 2) . " KB";
|
||||
} else if ($size < $gb) {
|
||||
return round($size / $mb, 2) . " MB";
|
||||
} else if ($size < $tb) {
|
||||
return round($size / $gb, 2) . " GB";
|
||||
} else {
|
||||
return round($size / $tb, 2) . " TB";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a human readable file size to bytes.
|
||||
*
|
||||
* @param string $v Size
|
||||
* @return integer
|
||||
*/
|
||||
public static function str2bytes($v)
|
||||
{
|
||||
$v = trim($v);
|
||||
$last = strtolower(substr($v, -1, 1));
|
||||
$v = (float) substr($v, 0, -1);
|
||||
switch ($last) {
|
||||
case 'g':
|
||||
$v *= 1024;
|
||||
case 'm':
|
||||
$v *= 1024;
|
||||
case 'k':
|
||||
$v *= 1024;
|
||||
}
|
||||
return $v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload status
|
||||
*
|
||||
* Returns true if upload status is ok, throws an exception instead.
|
||||
*
|
||||
* @param array $file File array as found in $_FILES
|
||||
* @return boolean
|
||||
*/
|
||||
public static function uploadStatus($file)
|
||||
{
|
||||
if (!isset($file['error'])) {
|
||||
throw new Exception(__('Not an uploaded file.'));
|
||||
}
|
||||
|
||||
switch ($file['error']) {
|
||||
case UPLOAD_ERR_OK:
|
||||
return true;
|
||||
case UPLOAD_ERR_INI_SIZE:
|
||||
case UPLOAD_ERR_FORM_SIZE:
|
||||
throw new Exception(__('The uploaded file exceeds the maximum file size allowed.'));
|
||||
return false;
|
||||
case UPLOAD_ERR_PARTIAL:
|
||||
throw new Exception(__('The uploaded file was only partially uploaded.'));
|
||||
return false;
|
||||
case UPLOAD_ERR_NO_FILE:
|
||||
throw new Exception(__('No file was uploaded.'));
|
||||
return false;
|
||||
case UPLOAD_ERR_NO_TMP_DIR:
|
||||
throw new Exception(__('Missing a temporary folder.'));
|
||||
return false;
|
||||
case UPLOAD_ERR_CANT_WRITE:
|
||||
throw new Exception(__('Failed to write file to disk.'));
|
||||
return false;
|
||||
case UPLOAD_ERR_EXTENSION:
|
||||
throw new Exception(__('A PHP extension stopped the file upload.'));
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
# Packages generation methods
|
||||
#
|
||||
/**
|
||||
* Recursive directory scanning
|
||||
*
|
||||
* Returns an array of a given directory's content. The array contains
|
||||
* two arrays: dirs and files. Directory's content is fetched recursively.
|
||||
*
|
||||
* @param string $dirName Directory name
|
||||
* @param array $contents Contents array. Leave it empty
|
||||
* @return array
|
||||
*/
|
||||
public static function getDirList($dirName, &$contents = null)
|
||||
{
|
||||
if (!$contents) {
|
||||
$contents = ['dirs' => [], 'files' => []];
|
||||
}
|
||||
|
||||
$exclude_list = ['.', '..', '.svn'];
|
||||
$dirName = preg_replace('|/$|', '', $dirName);
|
||||
|
||||
if (!is_dir($dirName)) {
|
||||
throw new Exception(sprintf(__('%s is not a directory.'), $dirName));
|
||||
}
|
||||
|
||||
$contents['dirs'][] = $dirName;
|
||||
|
||||
$d = @dir($dirName);
|
||||
if ($d === false) {
|
||||
throw new Exception(__('Unable to open directory.'));
|
||||
}
|
||||
|
||||
while ($entry = $d->read()) {
|
||||
if (!in_array($entry, $exclude_list)) {
|
||||
if (is_dir($dirName . '/' . $entry)) {
|
||||
files::getDirList($dirName . '/' . $entry, $contents);
|
||||
} else {
|
||||
$contents['files'][] = $dirName . '/' . $entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
$d->close();
|
||||
|
||||
return $contents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filename cleanup
|
||||
*
|
||||
* Removes unwanted characters in a filename.
|
||||
*
|
||||
* @param string $n Filename
|
||||
* @return string
|
||||
*/
|
||||
public static function tidyFileName($n)
|
||||
{
|
||||
$n = text::deaccent($n);
|
||||
$n = preg_replace('/^[.]/u', '', $n);
|
||||
return preg_replace('/[^A-Za-z0-9._-]/u', '_', $n);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @class path
|
||||
* @brief Path manipulation utilities
|
||||
*
|
||||
* @package Clearbricks
|
||||
* @subpackage Common
|
||||
*/
|
||||
class path
|
||||
{
|
||||
/**
|
||||
* Returns the real path of a file.
|
||||
*
|
||||
* If parameter $strict is true, file should exist. Returns false if
|
||||
* file does not exist.
|
||||
*
|
||||
* @param string $p Filename
|
||||
* @param boolean $strict File should exists
|
||||
* @return string
|
||||
*/
|
||||
public static function real($p, $strict = true)
|
||||
{
|
||||
$os = (DIRECTORY_SEPARATOR == '\\') ? 'win' : 'nix';
|
||||
|
||||
# Absolute path?
|
||||
if ($os == 'win') {
|
||||
$_abs = preg_match('/^\w+:/', $p);
|
||||
} else {
|
||||
$_abs = substr($p, 0, 1) == '/';
|
||||
}
|
||||
|
||||
# Standard path form
|
||||
if ($os == 'win') {
|
||||
$p = str_replace('\\', '/', $p);
|
||||
}
|
||||
|
||||
# Adding root if !$_abs
|
||||
if (!$_abs) {
|
||||
$p = dirname($_SERVER['SCRIPT_FILENAME']) . '/' . $p;
|
||||
}
|
||||
|
||||
# Clean up
|
||||
$p = preg_replace('|/+|', '/', $p);
|
||||
|
||||
if (strlen($p) > 1) {
|
||||
$p = preg_replace('|/$|', '', $p);
|
||||
}
|
||||
|
||||
$_start = '';
|
||||
if ($os == 'win') {
|
||||
list($_start, $p) = explode(':', $p);
|
||||
$_start .= ':/';
|
||||
} else {
|
||||
$_start = '/';
|
||||
}
|
||||
$p = substr($p, 1);
|
||||
|
||||
# Go through
|
||||
$P = explode('/', $p);
|
||||
$res = [];
|
||||
|
||||
for ($i = 0; $i < count($P); $i++) {
|
||||
if ($P[$i] == '.') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($P[$i] == '..') {
|
||||
if (count($res) > 0) {
|
||||
array_pop($res);
|
||||
}
|
||||
} else {
|
||||
array_push($res, $P[$i]);
|
||||
}
|
||||
}
|
||||
|
||||
$p = $_start . implode('/', $res);
|
||||
|
||||
if ($strict && !@file_exists($p)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a clean file path
|
||||
*
|
||||
* @param string $p File path
|
||||
* @return string
|
||||
*/
|
||||
public static function clean($p)
|
||||
{
|
||||
$p = str_replace('..', '', $p);
|
||||
$p = preg_replace('|/{2,}|', '/', $p);
|
||||
$p = preg_replace('|/$|', '', $p);
|
||||
|
||||
return $p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Path information
|
||||
*
|
||||
* Returns an array of information:
|
||||
* - dirname
|
||||
* - basename
|
||||
* - extension
|
||||
* - base (basename without extension)
|
||||
*
|
||||
* @param string $f File path
|
||||
*/
|
||||
public static function info($f)
|
||||
{
|
||||
$p = pathinfo($f);
|
||||
$res = [];
|
||||
|
||||
$res['dirname'] = $p['dirname'];
|
||||
$res['basename'] = $p['basename'];
|
||||
$res['extension'] = isset($p['extension']) ? $p['extension'] : '';
|
||||
$res['base'] = preg_replace('/\.' . preg_quote($res['extension'], '/') . '$/', '', $res['basename']);
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Full path with root
|
||||
*
|
||||
* Returns a path with root concatenation unless path begins with a slash
|
||||
*
|
||||
* @param string $p File path
|
||||
* @param string $root Root path
|
||||
* @return string
|
||||
*/
|
||||
public static function fullFromRoot($p, $root)
|
||||
{
|
||||
if (substr($p, 0, 1) == '/') {
|
||||
return $p;
|
||||
}
|
||||
|
||||
return $root . '/' . $p;
|
||||
}
|
||||
}
|
||||
746
dotclear._no/inc/libs/clearbricks/common/lib.form.php
Normal file
746
dotclear._no/inc/libs/clearbricks/common/lib.form.php
Normal file
@ -0,0 +1,746 @@
|
||||
<?php
|
||||
/**
|
||||
* @class form
|
||||
* @brief HTML Forms creation helpers
|
||||
*
|
||||
* @package Clearbricks
|
||||
* @subpackage Common
|
||||
*
|
||||
* @copyright Olivier Meunier & Association Dotclear
|
||||
* @copyright GPL-2.0-only
|
||||
*/
|
||||
|
||||
class form
|
||||
{
|
||||
/**
|
||||
* return id and name from given argument
|
||||
*
|
||||
* @param string|array $nid input argument
|
||||
* @param string &$name returned name
|
||||
* @param string &$id returned id
|
||||
*
|
||||
* @static
|
||||
* @access private
|
||||
*/
|
||||
private static function getNameAndId($nid, &$name, &$id)
|
||||
{
|
||||
if (is_array($nid)) {
|
||||
$name = $nid[0];
|
||||
$id = !empty($nid[1]) ? $nid[1] : null;
|
||||
} else {
|
||||
$name = $id = $nid;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* return an associative array of optional parameters of a class method
|
||||
*
|
||||
* @param string $class class name
|
||||
* @param string $method method name
|
||||
* @return array
|
||||
*
|
||||
* @static
|
||||
* @access private
|
||||
*/
|
||||
private static function getDefaults($class, $method)
|
||||
{
|
||||
$options = [];
|
||||
$reflect = new ReflectionMethod($class, $method);
|
||||
foreach ($reflect->getParameters() as $param) {
|
||||
if ($param->isOptional()) {
|
||||
$options[$param->getName()] = $param->getDefaultValue();
|
||||
}
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Select Box
|
||||
*
|
||||
* Returns HTML code for a select box.
|
||||
* **$nid** could be a string or an array of name and ID.
|
||||
* **$data** is an array with option titles keys and values in values
|
||||
* or an array of object of type {@link formSelectOption}. If **$data** is an array of
|
||||
* arrays, optgroups will be created.
|
||||
*
|
||||
* **$default** could be a string or an associative array of any of optional parameters:
|
||||
*
|
||||
* ```php
|
||||
* form::combo(['name', 'id'], $data, ['class' => 'maximal', 'extra_html' => 'data-language="php"']);
|
||||
* ```
|
||||
*
|
||||
* @uses formSelectOption
|
||||
*
|
||||
* @param string|array $nid Element ID and name
|
||||
* @param mixed $data Select box data
|
||||
* @param string|array $default Default value in select box | associative array of optional parameters
|
||||
* @param string $class Element class name
|
||||
* @param string $tabindex Element tabindex
|
||||
* @param boolean $disabled True if disabled
|
||||
* @param string $extra_html Extra HTML attributes
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @static
|
||||
*/
|
||||
public static function combo($nid, $data, $default = '', $class = '', $tabindex = '',
|
||||
$disabled = false, $extra_html = '') {
|
||||
|
||||
self::getNameAndId($nid, $name, $id);
|
||||
if (func_num_args() > 2 && is_array($default)) {
|
||||
// Cope with associative array of optional parameters
|
||||
$options = self::getDefaults(__CLASS__, __FUNCTION__);
|
||||
extract(array_merge($options, array_intersect_key($default, $options)));
|
||||
}
|
||||
|
||||
return '<select name="' . $name . '" ' .
|
||||
|
||||
($id ? 'id="' . $id . '" ' : '') .
|
||||
($class ? 'class="' . $class . '" ' : '') .
|
||||
($tabindex ? 'tabindex="' . $tabindex . '" ' : '') .
|
||||
($disabled ? 'disabled="disabled" ' : '') .
|
||||
$extra_html .
|
||||
|
||||
'>' . "\n" .
|
||||
self::comboOptions($data, $default) .
|
||||
'</select>' . "\n";
|
||||
}
|
||||
|
||||
private static function comboOptions($data, $default)
|
||||
{
|
||||
$res = '';
|
||||
$option = '<option value="%1$s"%3$s>%2$s</option>' . "\n";
|
||||
$optgroup = '<optgroup label="%1$s">' . "\n" . '%2$s' . "</optgroup>\n";
|
||||
|
||||
foreach ($data as $k => $v) {
|
||||
if (is_array($v)) {
|
||||
$res .= sprintf($optgroup, $k, self::comboOptions($v, $default));
|
||||
} elseif ($v instanceof formSelectOption) {
|
||||
$res .= $v->render($default);
|
||||
} else {
|
||||
$s = ((string) $v == (string) $default) ? ' selected="selected"' : '';
|
||||
$res .= sprintf($option, $v, $k, $s);
|
||||
}
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Radio button
|
||||
*
|
||||
* Returns HTML code for a radio button.
|
||||
* $nid could be a string or an array of name and ID.
|
||||
* $checked could be a boolean or an associative array of any of optional parameters
|
||||
*
|
||||
* @param string|array $nid Element ID and name
|
||||
* @param string $value Element value
|
||||
* @param boolean|array $checked True if checked | associative array of optional parameters
|
||||
* @param string $class Element class name
|
||||
* @param string $tabindex Element tabindex
|
||||
* @param boolean $disabled True if disabled
|
||||
* @param string $extra_html Extra HTML attributes
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @static
|
||||
*/
|
||||
public static function radio($nid, $value, $checked = '', $class = '', $tabindex = '',
|
||||
$disabled = false, $extra_html = '') {
|
||||
|
||||
self::getNameAndId($nid, $name, $id);
|
||||
if (func_num_args() > 2 && is_array($checked)) {
|
||||
// Cope with associative array of optional parameters
|
||||
$options = self::getDefaults(__CLASS__, __FUNCTION__);
|
||||
extract(array_merge($options, array_intersect_key($checked, $options)));
|
||||
}
|
||||
|
||||
return '<input type="radio" name="' . $name . '" value="' . $value . '" ' .
|
||||
|
||||
($id ? 'id="' . $id . '" ' : '') .
|
||||
($checked ? 'checked="checked" ' : '') .
|
||||
($class ? 'class="' . $class . '" ' : '') .
|
||||
($tabindex ? 'tabindex="' . $tabindex . '" ' : '') .
|
||||
($disabled ? 'disabled="disabled" ' : '') .
|
||||
$extra_html .
|
||||
|
||||
'/>' . "\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Checkbox
|
||||
*
|
||||
* Returns HTML code for a checkbox.
|
||||
* $nid could be a string or an array of name and ID.
|
||||
* $checked could be a boolean or an associative array of any of optional parameters
|
||||
*
|
||||
* @param string|array $nid Element ID and name
|
||||
* @param string $value Element value
|
||||
* @param boolean|array $checked True if checked | associative array of optional parameters
|
||||
* @param string $class Element class name
|
||||
* @param string $tabindex Element tabindex
|
||||
* @param boolean $disabled True if disabled
|
||||
* @param string $extra_html Extra HTML attributes
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @static
|
||||
*/
|
||||
public static function checkbox($nid, $value, $checked = '', $class = '', $tabindex = '',
|
||||
$disabled = false, $extra_html = '') {
|
||||
|
||||
self::getNameAndId($nid, $name, $id);
|
||||
if (func_num_args() > 2 && is_array($checked)) {
|
||||
// Cope with associative array of optional parameters
|
||||
$options = self::getDefaults(__CLASS__, __FUNCTION__);
|
||||
extract(array_merge($options, array_intersect_key($checked, $options)));
|
||||
}
|
||||
|
||||
return '<input type="checkbox" name="' . $name . '" value="' . $value . '" ' .
|
||||
|
||||
($id ? 'id="' . $id . '" ' : '') .
|
||||
($checked ? 'checked="checked" ' : '') .
|
||||
($class ? 'class="' . $class . '" ' : '') .
|
||||
($tabindex ? 'tabindex="' . $tabindex . '" ' : '') .
|
||||
($disabled ? 'disabled="disabled" ' : '') .
|
||||
$extra_html .
|
||||
|
||||
' />' . "\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Input field
|
||||
*
|
||||
* Returns HTML code for an input field.
|
||||
* $nid could be a string or an array of name and ID.
|
||||
* $default could be a string or an associative array of any of optional parameters
|
||||
*
|
||||
* @param string|array $nid Element ID and name
|
||||
* @param integer $size Element size
|
||||
* @param integer $max Element maxlength
|
||||
* @param string|array $default Element value | associative array of optional parameters
|
||||
* @param string $class Element class name
|
||||
* @param string $tabindex Element tabindex
|
||||
* @param boolean $disabled True if disabled
|
||||
* @param string $extra_html Extra HTML attributes
|
||||
* @param boolean $required Element is required
|
||||
* @param string $type Input type
|
||||
* @param string $autocomplete Autocomplete attributes if relevant
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @static
|
||||
*/
|
||||
public static function field($nid, $size, $max, $default = '', $class = '', $tabindex = '',
|
||||
$disabled = false, $extra_html = '', $required = false, $type = 'text', $autocomplete = '') {
|
||||
|
||||
self::getNameAndId($nid, $name, $id);
|
||||
if (func_num_args() > 3 && is_array($default)) {
|
||||
// Cope with associative array of optional parameters
|
||||
$options = self::getDefaults(__CLASS__, __FUNCTION__);
|
||||
extract(array_merge($options, array_intersect_key($default, $options)));
|
||||
}
|
||||
|
||||
return '<input type="' . $type . '" size="' . $size . '" name="' . $name . '" ' .
|
||||
|
||||
($id ? 'id="' . $id . '" ' : '') .
|
||||
($max ? 'maxlength="' . $max . '" ' : '') .
|
||||
($default || $default === '0' ? 'value="' . $default . '" ' : '') .
|
||||
($class ? 'class="' . $class . '" ' : '') .
|
||||
($tabindex ? 'tabindex="' . $tabindex . '" ' : '') .
|
||||
($disabled ? 'disabled="disabled" ' : '') .
|
||||
($required ? 'required ' : '') .
|
||||
($autocomplete ? 'autocomplete="' . $autocomplete . '" ' : '') .
|
||||
$extra_html .
|
||||
|
||||
' />' . "\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Password field
|
||||
*
|
||||
* Returns HTML code for a password field.
|
||||
* $nid could be a string or an array of name and ID.
|
||||
* $default could be a string or an associative array of any of optional parameters
|
||||
*
|
||||
* @uses form::field
|
||||
*
|
||||
* @param string|array $nid Element ID and name
|
||||
* @param integer $size Element size
|
||||
* @param integer $max Element maxlength
|
||||
* @param string|array $default Element value | associative array of optional parameters
|
||||
* @param string $class Element class name
|
||||
* @param string $tabindex Element tabindex
|
||||
* @param boolean $disabled True if disabled
|
||||
* @param string $extra_html Extra HTML attributes
|
||||
* @param boolean $required Element is required
|
||||
* @param string $autocomplete Autocomplete attributes if relevant (new-password/current-password)
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @static
|
||||
*/
|
||||
public static function password($nid, $size, $max, $default = '', $class = '', $tabindex = '',
|
||||
$disabled = false, $extra_html = '', $required = false, $autocomplete = '') {
|
||||
|
||||
if (func_num_args() > 3 && is_array($default)) {
|
||||
// Cope with associative array of optional parameters
|
||||
$options = self::getDefaults(__CLASS__, __FUNCTION__);
|
||||
extract(array_merge($options, array_intersect_key($default, $options)));
|
||||
}
|
||||
return self::field($nid, $size, $max, $default, $class, $tabindex, $disabled, $extra_html,
|
||||
$required, 'password', $autocomplete);
|
||||
}
|
||||
|
||||
/**
|
||||
* HTML5 Color field
|
||||
*
|
||||
* Returns HTML code for an input color field.
|
||||
* $nid could be a string or an array of name and ID.
|
||||
* $size could be a integer or an associative array of any of optional parameters
|
||||
*
|
||||
* @uses form::field
|
||||
*
|
||||
* @param string|array $nid Element ID and name
|
||||
* @param integer|array $size Element size | associative array of optional parameters
|
||||
* @param integer $max Element maxlength
|
||||
* @param string $default Element value
|
||||
* @param string $class Element class name
|
||||
* @param string $tabindex Element tabindex
|
||||
* @param boolean $disabled True if disabled
|
||||
* @param string $extra_html Extra HTML attributes
|
||||
* @param boolean $required Element is required
|
||||
* @param string $autocomplete Autocomplete attributes if relevant
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @static
|
||||
*/
|
||||
public static function color($nid, $size = 7, $max = 7, $default = '', $class = '', $tabindex = '',
|
||||
$disabled = false, $extra_html = '', $required = false, $autocomplete = '') {
|
||||
|
||||
if (func_num_args() > 1 && is_array($size)) {
|
||||
// Cope with associative array of optional parameters
|
||||
$options = self::getDefaults(__CLASS__, __FUNCTION__);
|
||||
extract(array_merge($options, array_intersect_key($size, $options)));
|
||||
}
|
||||
return self::field($nid, $size, $max, $default, $class, $tabindex, $disabled, $extra_html,
|
||||
$required, 'color', $autocomplete);
|
||||
}
|
||||
|
||||
/**
|
||||
* HTML5 Email field
|
||||
*
|
||||
* Returns HTML code for an input email field.
|
||||
* $nid could be a string or an array of name and ID.
|
||||
* $size could be a integer or an associative array of any of optional parameters
|
||||
*
|
||||
* @uses form::field
|
||||
*
|
||||
* @param string|array $nid Element ID and name
|
||||
* @param integer|array $size Element size | associative array of optional parameters
|
||||
* @param integer $max Element maxlength
|
||||
* @param string $default Element value
|
||||
* @param string $class Element class name
|
||||
* @param string $tabindex Element tabindex
|
||||
* @param boolean $disabled True if disabled
|
||||
* @param string $extra_html Extra HTML attributes
|
||||
* @param boolean $required Element is required
|
||||
* @param string $autocomplete Autocomplete attributes if relevant
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @static
|
||||
*/
|
||||
public static function email($nid, $size = 20, $max = 255, $default = '', $class = '', $tabindex = '',
|
||||
$disabled = false, $extra_html = '', $required = false, $autocomplete = '') {
|
||||
|
||||
if (func_num_args() > 1 && is_array($size)) {
|
||||
// Cope with associative array of optional parameters
|
||||
$options = self::getDefaults(__CLASS__, __FUNCTION__);
|
||||
extract(array_merge($options, array_intersect_key($size, $options)));
|
||||
}
|
||||
return self::field($nid, $size, $max, $default, $class, $tabindex, $disabled, $extra_html,
|
||||
$required, 'email', $autocomplete);
|
||||
}
|
||||
|
||||
/**
|
||||
* HTML5 URL field
|
||||
*
|
||||
* Returns HTML code for an input (absolute) URL field.
|
||||
* $nid could be a string or an array of name and ID.
|
||||
* $size could be a integer or an associative array of any of optional parameters
|
||||
*
|
||||
* @uses form::field
|
||||
*
|
||||
* @param string|array $nid Element ID and name
|
||||
* @param integer|array $size Element size | associative array of optional parameters
|
||||
* @param integer $max Element maxlength
|
||||
* @param string $default Element value
|
||||
* @param string $class Element class name
|
||||
* @param string $tabindex Element tabindex
|
||||
* @param boolean $disabled True if disabled
|
||||
* @param string $extra_html Extra HTML attributes
|
||||
* @param boolean $required Element is required
|
||||
* @param string $autocomplete Autocomplete attributes if relevant
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @static
|
||||
*/
|
||||
public static function url($nid, $size = 20, $max = 255, $default = '', $class = '', $tabindex = '',
|
||||
$disabled = false, $extra_html = '', $required = false, $autocomplete = '') {
|
||||
|
||||
if (func_num_args() > 1 && is_array($size)) {
|
||||
// Cope with associative array of optional parameters
|
||||
$options = self::getDefaults(__CLASS__, __FUNCTION__);
|
||||
extract(array_merge($options, array_intersect_key($size, $options)));
|
||||
}
|
||||
return self::field($nid, $size, $max, $default, $class, $tabindex, $disabled, $extra_html,
|
||||
$required, 'url', $autocomplete);
|
||||
}
|
||||
|
||||
/**
|
||||
* HTML5 Datetime (local) field
|
||||
*
|
||||
* Returns HTML code for an input datetime field.
|
||||
* $nid could be a string or an array of name and ID.
|
||||
* $size could be a integer or an associative array of any of optional parameters
|
||||
*
|
||||
* @uses form::field
|
||||
*
|
||||
* @param string|array $nid Element ID and name
|
||||
* @param integer|array $size Element size | associative array of optional parameters
|
||||
* @param integer $max Element maxlength
|
||||
* @param string $default Element value (in YYYY-MM-DDThh:mm format)
|
||||
* @param string $class Element class name
|
||||
* @param string $tabindex Element tabindex
|
||||
* @param boolean $disabled True if disabled
|
||||
* @param string $extra_html Extra HTML attributes
|
||||
* @param boolean $required Element is required
|
||||
* @param string $autocomplete Autocomplete attributes if relevant
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @static
|
||||
*/
|
||||
public static function datetime($nid, $size = 16, $max = 16, $default = '', $class = '', $tabindex = '',
|
||||
$disabled = false, $extra_html = '', $required = false, $autocomplete = '') {
|
||||
|
||||
if (func_num_args() > 1 && is_array($size)) {
|
||||
// Cope with associative array of optional parameters
|
||||
$options = self::getDefaults(__CLASS__, __FUNCTION__);
|
||||
extract(array_merge($options, array_intersect_key($size, $options)));
|
||||
}
|
||||
// Cope with unimplemented input type for some browser (type="text" + pattern + placeholder)
|
||||
if (strpos(strtolower($extra_html), 'pattern=') === false) {
|
||||
$extra_html .= ' pattern="[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}"';
|
||||
}
|
||||
if (strpos(strtolower($extra_html), 'placeholder') === false) {
|
||||
$extra_html .= ' placeholder="1962-05-13T14:45"';
|
||||
}
|
||||
return self::field($nid, $size, $max, $default, $class, $tabindex, $disabled, $extra_html,
|
||||
$required, 'datetime-local', $autocomplete);
|
||||
}
|
||||
|
||||
/**
|
||||
* HTML5 Date field
|
||||
*
|
||||
* Returns HTML code for an input date field.
|
||||
* $nid could be a string or an array of name and ID.
|
||||
* $size could be a integer or an associative array of any of optional parameters
|
||||
*
|
||||
* @uses form::field
|
||||
*
|
||||
* @param string|array $nid Element ID and name
|
||||
* @param integer|array $size Element size | associative array of optional parameters
|
||||
* @param integer $max Element maxlength
|
||||
* @param string $default Element value (in YYYY-MM-DD format)
|
||||
* @param string $class Element class name
|
||||
* @param string $tabindex Element tabindex
|
||||
* @param boolean $disabled True if disabled
|
||||
* @param string $extra_html Extra HTML attributes
|
||||
* @param boolean $required Element is required
|
||||
* @param string $autocomplete Autocomplete attributes if relevant
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @static
|
||||
*/
|
||||
public static function date($nid, $size = 10, $max = 10, $default = '', $class = '', $tabindex = '',
|
||||
$disabled = false, $extra_html = '', $required = false, $autocomplete = '') {
|
||||
|
||||
if (func_num_args() > 1 && is_array($size)) {
|
||||
// Cope with associative array of optional parameters
|
||||
$options = self::getDefaults(__CLASS__, __FUNCTION__);
|
||||
extract(array_merge($options, array_intersect_key($size, $options)));
|
||||
}
|
||||
// Cope with unimplemented input type for some browser (type="text" + pattern + placeholder)
|
||||
if (strpos(strtolower($extra_html), 'pattern=') === false) {
|
||||
$extra_html .= ' pattern="[0-9]{4}-[0-9]{2}-[0-9]{2}"';
|
||||
}
|
||||
if (strpos(strtolower($extra_html), 'placeholder') === false) {
|
||||
$extra_html .= ' placeholder="1962-05-13"';
|
||||
}
|
||||
return self::field($nid, $size, $max, $default, $class, $tabindex, $disabled, $extra_html,
|
||||
$required, 'date', $autocomplete);
|
||||
}
|
||||
|
||||
/**
|
||||
* HTML5 Time (local) field
|
||||
*
|
||||
* Returns HTML code for an input time field.
|
||||
* $nid could be a string or an array of name and ID.
|
||||
* $size could be a integer or an associative array of any of optional parameters
|
||||
*
|
||||
* @uses form::field
|
||||
*
|
||||
* @param string|array $nid Element ID and name
|
||||
* @param integer|array $size Element size | associative array of optional parameters
|
||||
* @param integer $max Element maxlength
|
||||
* @param string $default Element value (in hh:mm format)
|
||||
* @param string $class Element class name
|
||||
* @param string $tabindex Element tabindex
|
||||
* @param boolean $disabled True if disabled
|
||||
* @param string $extra_html Extra HTML attributes
|
||||
* @param boolean $required Element is required
|
||||
* @param string $autocomplete Autocomplete attributes if relevant
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @static
|
||||
*/
|
||||
public static function time($nid, $size = 5, $max = 5, $default = '', $class = '', $tabindex = '',
|
||||
$disabled = false, $extra_html = '', $required = false, $autocomplete = '') {
|
||||
|
||||
if (func_num_args() > 1 && is_array($size)) {
|
||||
// Cope with associative array of optional parameters
|
||||
$options = self::getDefaults(__CLASS__, __FUNCTION__);
|
||||
extract(array_merge($options, array_intersect_key($size, $options)));
|
||||
}
|
||||
// Cope with unimplemented input type for some browser (type="text" + pattern + placeholder)
|
||||
if (strpos(strtolower($extra_html), 'pattern=') === false) {
|
||||
$extra_html .= ' pattern="[0-9]{2}:[0-9]{2}"';
|
||||
}
|
||||
if (strpos(strtolower($extra_html), 'placeholder') === false) {
|
||||
$extra_html .= ' placeholder="14:45"';
|
||||
}
|
||||
return self::field($nid, $size, $max, $default, $class, $tabindex, $disabled, $extra_html,
|
||||
$required, 'time', $autocomplete);
|
||||
}
|
||||
|
||||
/**
|
||||
* HTML5 file field
|
||||
*
|
||||
* Returns HTML code for an input file field.
|
||||
* $nid could be a string or an array of name and ID.
|
||||
* $default could be a integer or an associative array of any of optional parameters
|
||||
*
|
||||
* @param string|array $nid Element ID and name
|
||||
* @param string|array $default Element value | associative array of optional parameters
|
||||
* @param string $class Element class name
|
||||
* @param string $tabindex Element tabindex
|
||||
* @param boolean $disabled True if disabled
|
||||
* @param string $extra_html Extra HTML attributes
|
||||
* @param boolean $required Element is required
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @static
|
||||
*/
|
||||
public static function file($nid, $default = '', $class = '', $tabindex = '', $disabled = false, $extra_html = '',
|
||||
$required = false) {
|
||||
|
||||
self::getNameAndId($nid, $name, $id);
|
||||
if (func_num_args() > 1 && is_array($default)) {
|
||||
// Cope with associative array of optional parameters
|
||||
$options = self::getDefaults(__CLASS__, __FUNCTION__);
|
||||
extract(array_merge($options, array_intersect_key($default, $options)));
|
||||
}
|
||||
|
||||
return '<input type="file" ' . '" name="' . $name . '" ' .
|
||||
|
||||
($id ? 'id="' . $id . '" ' : '') .
|
||||
($default || $default === '0' ? 'value="' . $default . '" ' : '') .
|
||||
($class ? 'class="' . $class . '" ' : '') .
|
||||
($tabindex ? 'tabindex="' . $tabindex . '" ' : '') .
|
||||
($disabled ? 'disabled="disabled" ' : '') .
|
||||
($required ? 'required ' : '') .
|
||||
$extra_html .
|
||||
|
||||
' />' . "\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* HTML5 number input field
|
||||
*
|
||||
* Returns HTML code for an number input field.
|
||||
* $nid could be a string or an array of name and ID.
|
||||
* $min could be a string or an associative array of any of optional parameters
|
||||
*
|
||||
* @param string|array $nid Element ID and name
|
||||
* @param integer|array $min Element min value (may be negative) | associative array of optional parameters
|
||||
* @param integer $max Element max value (may be negative)
|
||||
* @param string $default Element value
|
||||
* @param string $class Element class name
|
||||
* @param string $tabindex Element tabindex
|
||||
* @param boolean $disabled True if disabled
|
||||
* @param string $extra_html Extra HTML attributes
|
||||
* @param boolean $required Element is required
|
||||
* @param string $autocomplete Autocomplete attributes if relevant
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @static
|
||||
*/
|
||||
public static function number($nid, $min = null, $max = null, $default = '', $class = '', $tabindex = '',
|
||||
$disabled = false, $extra_html = '', $required = false, $autocomplete = '') {
|
||||
|
||||
self::getNameAndId($nid, $name, $id);
|
||||
if (func_num_args() > 1 && is_array($min)) {
|
||||
// Cope with associative array of optional parameters
|
||||
$options = self::getDefaults(__CLASS__, __FUNCTION__);
|
||||
extract(array_merge($options, array_intersect_key($min, $options)));
|
||||
}
|
||||
|
||||
return '<input type="number" name="' . $name . '" ' .
|
||||
|
||||
($id ? 'id="' . $id . '" ' : '') .
|
||||
($min !== null ? 'min="' . $min . '" ' : '') .
|
||||
($max !== null ? 'max="' . $max . '" ' : '') .
|
||||
($default || $default === '0' ? 'value="' . $default . '" ' : '') .
|
||||
($class ? 'class="' . $class . '" ' : '') .
|
||||
($tabindex ? 'tabindex="' . $tabindex . '" ' : '') .
|
||||
($disabled ? 'disabled="disabled" ' : '') .
|
||||
($required ? 'required ' : '') .
|
||||
($autocomplete ? 'autocomplete="' . $autocomplete . '" ' : '') .
|
||||
$extra_html .
|
||||
|
||||
' />' . "\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Textarea
|
||||
*
|
||||
* Returns HTML code for a textarea.
|
||||
* $nid could be a string or an array of name and ID.
|
||||
* $default could be a string or an associative array of any of optional parameters
|
||||
*
|
||||
* @param string|array $nid Element ID and name
|
||||
* @param integer $cols Number of columns
|
||||
* @param integer $rows Number of rows
|
||||
* @param string|array $default Element value | associative array of optional parameters
|
||||
* @param string $class Element class name
|
||||
* @param string $tabindex Element tabindex
|
||||
* @param boolean $disabled True if disabled
|
||||
* @param string $extra_html Extra HTML attributes
|
||||
* @param boolean $required Element is required
|
||||
* @param string $autocomplete Autocomplete attributes if relevant
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @static
|
||||
*/
|
||||
public static function textArea($nid, $cols, $rows, $default = '', $class = '',
|
||||
$tabindex = '', $disabled = false, $extra_html = '', $required = false, $autocomplete = '') {
|
||||
|
||||
self::getNameAndId($nid, $name, $id);
|
||||
if (func_num_args() > 3 && is_array($default)) {
|
||||
// Cope with associative array of optional parameters
|
||||
$options = self::getDefaults(__CLASS__, __FUNCTION__);
|
||||
extract(array_merge($options, array_intersect_key($default, $options)));
|
||||
}
|
||||
|
||||
return '<textarea cols="' . $cols . '" rows="' . $rows . '" name="' . $name . '" ' .
|
||||
|
||||
($id ? 'id="' . $id . '" ' : '') .
|
||||
($tabindex != '' ? 'tabindex="' . $tabindex . '" ' : '') .
|
||||
($class ? 'class="' . $class . '" ' : '') .
|
||||
($disabled ? 'disabled="disabled" ' : '') .
|
||||
($required ? 'required ' : '') .
|
||||
($autocomplete ? 'autocomplete="' . $autocomplete . '" ' : '') .
|
||||
$extra_html . '>' . $default . '</textarea>' . "\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Hidden field
|
||||
*
|
||||
* Returns HTML code for an hidden field. $nid could be a string or an array of
|
||||
* name and ID.
|
||||
*
|
||||
* @param string|array $nid Element ID and name
|
||||
* @param string $value Element value
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @static
|
||||
*/
|
||||
public static function hidden($nid, $value)
|
||||
{
|
||||
self::getNameAndId($nid, $name, $id);
|
||||
|
||||
return '<input type="hidden" name="' . $name . '" value="' . $value . '" ' .
|
||||
|
||||
($id ? 'id="' . $id . '" ' : '') .
|
||||
|
||||
' />' . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @class formSelectOption
|
||||
* @brief HTML Forms creation helpers
|
||||
*
|
||||
* @package Clearbricks
|
||||
* @subpackage Common
|
||||
*/
|
||||
class formSelectOption
|
||||
{
|
||||
public $name; ///< Option name
|
||||
public $value; ///< Option value
|
||||
public $class_name; ///< Element class name
|
||||
public $html; ///< Extra HTML attributes
|
||||
|
||||
/**
|
||||
* sprintf template for option
|
||||
* @var string $option
|
||||
* @access private
|
||||
*/
|
||||
private $option = '<option value="%1$s"%3$s>%2$s</option>' . "\n";
|
||||
|
||||
/**
|
||||
* Option constructor
|
||||
*
|
||||
* @param string $name Option name
|
||||
* @param string $value Option value
|
||||
* @param string $class_name Element class name
|
||||
* @param string $html Extra HTML attributes
|
||||
*/
|
||||
public function __construct($name, $value, $class_name = '', $html = '')
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->value = $value;
|
||||
$this->class_name = $class_name;
|
||||
$this->html = $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Option renderer
|
||||
*
|
||||
* Returns option HTML code
|
||||
*
|
||||
* @param boolean $default Option is selected
|
||||
* @return string
|
||||
*/
|
||||
public function render($default)
|
||||
{
|
||||
$attr = $this->html ? ' ' . $this->html : '';
|
||||
$attr .= $this->class_name ? ' class="' . $this->class_name . '"' : '';
|
||||
|
||||
if ($this->value == $default) {
|
||||
$attr .= ' selected="selected"';
|
||||
}
|
||||
|
||||
return sprintf($this->option, $this->value, $this->name, $attr) . "\n";
|
||||
}
|
||||
}
|
||||
179
dotclear._no/inc/libs/clearbricks/common/lib.html.php
Normal file
179
dotclear._no/inc/libs/clearbricks/common/lib.html.php
Normal file
@ -0,0 +1,179 @@
|
||||
<?php
|
||||
/**
|
||||
* @class html
|
||||
* @brief HTML utilities
|
||||
*
|
||||
* @package Clearbricks
|
||||
* @subpackage Common
|
||||
*
|
||||
* @copyright Olivier Meunier & Association Dotclear
|
||||
* @copyright GPL-2.0-only
|
||||
*/
|
||||
|
||||
class html
|
||||
{
|
||||
public static $url_root;
|
||||
public static $absolute_regs = []; ///< Array of regular expression for {@link absoluteURLs()}
|
||||
|
||||
/**
|
||||
* HTML escape
|
||||
*
|
||||
* Replaces HTML special characters by entities.
|
||||
*
|
||||
* @param string $str String to escape
|
||||
* @return string
|
||||
*/
|
||||
public static function escapeHTML($str)
|
||||
{
|
||||
return htmlspecialchars($str, ENT_COMPAT, 'UTF-8');
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode HTML entities
|
||||
*
|
||||
* Returns a string with all entities decoded.
|
||||
*
|
||||
* @param string $str String to protect
|
||||
* @param string $keep_special Keep special characters: > < &
|
||||
* @return string
|
||||
*/
|
||||
public static function decodeEntities($str, $keep_special = false)
|
||||
{
|
||||
if ($keep_special) {
|
||||
$str = str_replace(
|
||||
['&', '>', '<'],
|
||||
['&amp;', '&gt;', '&lt;'],
|
||||
$str);
|
||||
}
|
||||
|
||||
# Some extra replacements
|
||||
$extra = [
|
||||
''' => "'"
|
||||
];
|
||||
|
||||
$str = str_replace(array_keys($extra), array_values($extra), $str);
|
||||
|
||||
return html_entity_decode($str, ENT_QUOTES, 'UTF-8');
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove markup
|
||||
*
|
||||
* Removes every tags, comments, cdata from string
|
||||
*
|
||||
* @param string $str String to clean
|
||||
* @return string
|
||||
*/
|
||||
public static function clean($str)
|
||||
{
|
||||
$str = strip_tags($str);
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Javascript escape
|
||||
*
|
||||
* Returns a protected JavaScript string
|
||||
*
|
||||
* @param string $str String to protect
|
||||
* @return string
|
||||
*/
|
||||
public static function escapeJS($str)
|
||||
{
|
||||
$str = htmlspecialchars($str, ENT_NOQUOTES, 'UTF-8');
|
||||
$str = str_replace("'", "\'", $str);
|
||||
$str = str_replace('"', '\"', $str);
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* URL escape
|
||||
*
|
||||
* Returns an escaped URL string for HTML content
|
||||
*
|
||||
* @param string $str String to escape
|
||||
* @return string
|
||||
*/
|
||||
public static function escapeURL($str)
|
||||
{
|
||||
return str_replace('&', '&', $str);
|
||||
}
|
||||
|
||||
/**
|
||||
* URL sanitize
|
||||
*
|
||||
* Encode every parts between / in url
|
||||
*
|
||||
* @param string $str String to satinyze
|
||||
* @return string
|
||||
*/
|
||||
public static function sanitizeURL($str)
|
||||
{
|
||||
return str_replace('%2F', '/', rawurlencode($str));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove host in URL
|
||||
*
|
||||
* Removes host part in URL
|
||||
*
|
||||
* @param string $url URL to transform
|
||||
* @return string
|
||||
*/
|
||||
public static function stripHostURL($url)
|
||||
{
|
||||
return preg_replace('|^[a-z]{3,}://.*?(/.*$)|', '$1', $url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set links to absolute ones
|
||||
*
|
||||
* Appends $root URL to URIs attributes in $str.
|
||||
*
|
||||
* @param string $str HTML to transform
|
||||
* @param string $root Base URL
|
||||
* @return string
|
||||
*/
|
||||
public static function absoluteURLs($str, $root)
|
||||
{
|
||||
self::$url_root = $root;
|
||||
$attr = 'action|background|cite|classid|code|codebase|data|download|formaction|href|longdesc|profile|src|usemap';
|
||||
|
||||
$str = preg_replace_callback('/((?:' . $attr . ')=")(.*?)(")/msu', ['self', 'absoluteURLHandler'], $str);
|
||||
|
||||
foreach (self::$absolute_regs as $r) {
|
||||
$str = preg_replace_callback($r, ['self', 'absoluteURLHandler'], $str);
|
||||
}
|
||||
|
||||
self::$url_root = null;
|
||||
return $str;
|
||||
}
|
||||
|
||||
private static function absoluteURLHandler($m)
|
||||
{
|
||||
$url = $m[2];
|
||||
|
||||
$link = str_replace('%', '%%', $m[1]) . '%s' . str_replace('%', '%%', $m[3]);
|
||||
$host = preg_replace('|^([a-z]{3,}://)(.*?)/(.*)$|', '$1$2', self::$url_root);
|
||||
|
||||
$parse = parse_url($m[2]);
|
||||
if (empty($parse['scheme'])) {
|
||||
if (strpos($url, '//') === 0) {
|
||||
// Nothing to do. Already an absolute URL.
|
||||
} elseif (strpos($url, '/') === 0) {
|
||||
// Beginning by a / return host + url
|
||||
$url = $host . $url;
|
||||
} elseif (strpos($url, '#') === 0) {
|
||||
// Beginning by a # return root + hash
|
||||
$url = self::$url_root . $url;
|
||||
} elseif (preg_match('|/$|', self::$url_root)) {
|
||||
// Root is ending by / return root + url
|
||||
$url = self::$url_root . $url;
|
||||
} else {
|
||||
$url = dirname(self::$url_root) . '/' . $url;
|
||||
}
|
||||
}
|
||||
|
||||
return sprintf($link, $url);
|
||||
}
|
||||
}
|
||||
474
dotclear._no/inc/libs/clearbricks/common/lib.http.php
Normal file
474
dotclear._no/inc/libs/clearbricks/common/lib.http.php
Normal file
@ -0,0 +1,474 @@
|
||||
<?php
|
||||
/**
|
||||
* @class http
|
||||
* @brief HTTP utilities
|
||||
*
|
||||
* @package Clearbricks
|
||||
* @subpackage Common
|
||||
*
|
||||
* @copyright Olivier Meunier & Association Dotclear
|
||||
* @copyright GPL-2.0-only
|
||||
*/
|
||||
|
||||
class http
|
||||
{
|
||||
public static $https_scheme_on_443 = false; ///< boolean: Force HTTPS scheme on server port 443 in {@link getHost()}
|
||||
public static $cache_max_age = 0; ///< integer: Cache max age for {@link cache()}
|
||||
public static $reverse_proxy = false; ///< bolean: use X-FORWARD headers on getHost();
|
||||
|
||||
/**
|
||||
* Self root URI
|
||||
*
|
||||
* Returns current scheme, host and port.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getHost()
|
||||
{
|
||||
if (self::$reverse_proxy && isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
|
||||
//admin have choose to allow a reverse proxy,
|
||||
//and HTTP_X_FORWARDED_FOR header means it's beeing using
|
||||
|
||||
if (!isset($_SERVER['HTTP_X_FORWARDED_PROTO'])) {
|
||||
throw new Exception('Reverse proxy parametter is setted, header HTTP_X_FORWARDED_FOR is found but not the X-Forwarded-Proto. Please check your reverse proxy server settings');
|
||||
}
|
||||
|
||||
$scheme = $_SERVER['HTTP_X_FORWARDED_PROTO'];
|
||||
|
||||
$name_port_array = explode(":", $_SERVER['HTTP_HOST']);
|
||||
$server_name = $name_port_array[0];
|
||||
|
||||
$port = isset($name_port_array[1]) ? ':' . $name_port_array[1] : '';
|
||||
if (($port == ':80' && $scheme == 'http') || ($port == ':443' && $scheme == 'https')) {
|
||||
$port = '';
|
||||
}
|
||||
return $scheme . '://' . $server_name . $port;
|
||||
}
|
||||
|
||||
$server_name = explode(':', $_SERVER['HTTP_HOST']);
|
||||
$server_name = $server_name[0];
|
||||
if (self::$https_scheme_on_443 && $_SERVER['SERVER_PORT'] == '443') {
|
||||
$scheme = 'https';
|
||||
$port = '';
|
||||
} elseif (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
|
||||
$scheme = 'https';
|
||||
$port = !in_array($_SERVER['SERVER_PORT'], ['80', '443']) ? ':' . $_SERVER['SERVER_PORT'] : '';
|
||||
} else {
|
||||
$scheme = 'http';
|
||||
$port = ($_SERVER['SERVER_PORT'] != '80') ? ':' . $_SERVER['SERVER_PORT'] : '';
|
||||
}
|
||||
|
||||
return $scheme . '://' . $server_name . $port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Self root URI
|
||||
*
|
||||
* Returns current scheme and host from a static URL.
|
||||
*
|
||||
* @param string $url URL to retrieve the host from.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getHostFromURL($url)
|
||||
{
|
||||
preg_match('~^(?:((?:[a-z]+:)?//)|:(//))?(?:([^:\r\n]*?)/[^:\r\n]*|([^:\r\n]*))$~', $url, $matches);
|
||||
array_shift($matches);
|
||||
return join($matches);
|
||||
}
|
||||
|
||||
/**
|
||||
* Self URI
|
||||
*
|
||||
* Returns current URI with full hostname.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getSelfURI()
|
||||
{
|
||||
if (substr($_SERVER['REQUEST_URI'], 0, 1) != '/') {
|
||||
return self::getHost() . '/' . $_SERVER['REQUEST_URI'];
|
||||
} else {
|
||||
return self::getHost() . $_SERVER['REQUEST_URI'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare a full redirect URI from a relative or absolute URL
|
||||
*
|
||||
* @param string $page Relative URL
|
||||
* @return string full URI
|
||||
*/
|
||||
protected static function prepareRedirect($page)
|
||||
{
|
||||
if (preg_match('%^http[s]?://%', $page)) {
|
||||
$redir = $page;
|
||||
} else {
|
||||
$host = self::getHost();
|
||||
|
||||
if (substr($page, 0, 1) == '/') {
|
||||
$redir = $host . $page;
|
||||
} else {
|
||||
$dir = str_replace(DIRECTORY_SEPARATOR, '/', dirname($_SERVER['PHP_SELF']));
|
||||
if (substr($dir, -1) == '/') {
|
||||
$dir = substr($dir, 0, -1);
|
||||
}
|
||||
if ($dir == '.') {
|
||||
$dir = '';
|
||||
}
|
||||
$redir = $host . $dir . '/' . $page;
|
||||
}
|
||||
}
|
||||
return $redir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect
|
||||
*
|
||||
* Performs a conforming HTTP redirect for a relative URL.
|
||||
*
|
||||
* @param string $page Relative URL
|
||||
*/
|
||||
public static function redirect($page)
|
||||
{
|
||||
# Close session if exists
|
||||
if (session_id()) {
|
||||
session_write_close();
|
||||
}
|
||||
|
||||
header('Location: ' . self::prepareRedirect($page));
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Concat URL and path
|
||||
*
|
||||
* Appends a path to a given URL. If path begins with "/" it will replace the
|
||||
* original URL path.
|
||||
*
|
||||
* @param string $url URL
|
||||
* @param string $path Path to append
|
||||
* @return string
|
||||
*/
|
||||
public static function concatURL($url, $path)
|
||||
{
|
||||
if (substr($url, -1, 1) != '/') {
|
||||
$url .= '/';
|
||||
}
|
||||
|
||||
if (substr($path, 0, 1) != '/') {
|
||||
return $url . $path;
|
||||
}
|
||||
|
||||
return preg_replace('#^(.+?//.+?)/(.*)$#', '$1' . $path, $url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Real IP
|
||||
*
|
||||
* Returns the real client IP (or tries to do its best).
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function realIP()
|
||||
{
|
||||
return isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Client unique ID
|
||||
*
|
||||
* Returns a "almost" safe client unique ID.
|
||||
*
|
||||
* @param string $key HMAC key
|
||||
* @return string
|
||||
*/
|
||||
public static function browserUID($key)
|
||||
{
|
||||
$uid = '';
|
||||
$uid .= isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '';
|
||||
$uid .= isset($_SERVER['HTTP_ACCEPT_CHARSET']) ? $_SERVER['HTTP_ACCEPT_CHARSET'] : '';
|
||||
|
||||
return crypt::hmac($key, $uid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Client language
|
||||
*
|
||||
* Returns a two letters language code take from HTTP_ACCEPT_LANGUAGE.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getAcceptLanguage()
|
||||
{
|
||||
$dlang = '';
|
||||
if (!empty($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
|
||||
$acclang = explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']);
|
||||
$L = explode(';', $acclang[0]);
|
||||
$dlang = substr(trim($L[0]), 0, 2);
|
||||
}
|
||||
|
||||
return $dlang;
|
||||
}
|
||||
|
||||
/**
|
||||
* Client languages
|
||||
*
|
||||
* Returns an array of accepted langages ordered by priority.
|
||||
* can be a two letters language code or a xx-xx variant.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getAcceptLanguages()
|
||||
{
|
||||
$langs = [];
|
||||
if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
|
||||
|
||||
// break up string into pieces (languages and q factors)
|
||||
preg_match_all(
|
||||
'/([a-z]{1,8}(-[a-z]{1,8})?)\s*(;\s*q\s*=\s*(1|0\.[0-9]+))?/i',
|
||||
$_SERVER['HTTP_ACCEPT_LANGUAGE'],
|
||||
$lang_parse
|
||||
);
|
||||
|
||||
if (count($lang_parse[1])) {
|
||||
// create a list like "en" => 0.8
|
||||
$langs = array_combine($lang_parse[1], $lang_parse[4]);
|
||||
|
||||
// set default to 1 for any without q factor
|
||||
foreach ($langs as $lang => $val) {
|
||||
if ($val === '') {
|
||||
$langs[$lang] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// sort list based on value
|
||||
arsort($langs, SORT_NUMERIC);
|
||||
$langs = array_map('strtolower', array_keys($langs));
|
||||
}
|
||||
}
|
||||
return $langs;
|
||||
}
|
||||
|
||||
/**
|
||||
* HTTP Cache
|
||||
*
|
||||
* Sends HTTP cache headers (304) according to a list of files and an optionnal.
|
||||
* list of timestamps.
|
||||
*
|
||||
* @param array $files Files on which check mtime
|
||||
* @param array $mod_ts List of timestamps
|
||||
*/
|
||||
public static function cache($files, $mod_ts = [])
|
||||
{
|
||||
if (empty($files) || !is_array($files)) {
|
||||
return;
|
||||
}
|
||||
|
||||
array_walk($files, function (&$v) {
|
||||
$v = filemtime($v);
|
||||
});
|
||||
|
||||
$array_ts = array_merge($mod_ts, $files);
|
||||
|
||||
rsort($array_ts);
|
||||
$now = time();
|
||||
$ts = min($array_ts[0], $now);
|
||||
|
||||
$since = null;
|
||||
if (!empty($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
|
||||
$since = $_SERVER['HTTP_IF_MODIFIED_SINCE'];
|
||||
$since = preg_replace('/^(.*)(Mon|Tue|Wed|Thu|Fri|Sat|Sun)(.*)(GMT)(.*)/', '$2$3 GMT', $since);
|
||||
$since = strtotime($since);
|
||||
$since = ($since <= $now) ? $since : null;
|
||||
}
|
||||
|
||||
# Common headers list
|
||||
$headers[] = 'Last-Modified: ' . gmdate('D, d M Y H:i:s', $ts) . ' GMT';
|
||||
$headers[] = 'Cache-Control: must-revalidate, max-age=' . abs((integer) self::$cache_max_age);
|
||||
$headers[] = 'Pragma:';
|
||||
|
||||
if ($since >= $ts) {
|
||||
self::head(304, 'Not Modified');
|
||||
foreach ($headers as $v) {
|
||||
header($v);
|
||||
}
|
||||
exit;
|
||||
} else {
|
||||
header('Date: ' . gmdate('D, d M Y H:i:s', $now) . ' GMT');
|
||||
foreach ($headers as $v) {
|
||||
header($v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* HTTP Etag
|
||||
*
|
||||
* Sends HTTP cache headers (304) according to a list of etags in client request.
|
||||
*/
|
||||
public static function etag()
|
||||
{
|
||||
# We create an etag from all arguments
|
||||
$args = func_get_args();
|
||||
if (empty($args)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$etag = '"' . md5(implode('', $args)) . '"';
|
||||
unset($args);
|
||||
|
||||
header('ETag: ' . $etag);
|
||||
|
||||
# Do we have a previously sent content?
|
||||
if (!empty($_SERVER['HTTP_IF_NONE_MATCH'])) {
|
||||
foreach (explode(',', $_SERVER['HTTP_IF_NONE_MATCH']) as $i) {
|
||||
if (stripslashes(trim($i)) == $etag) {
|
||||
self::head(304, 'Not Modified');
|
||||
exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* HTTP Header
|
||||
*
|
||||
* Sends an HTTP code and message to client.
|
||||
*
|
||||
* @param string $code HTTP code
|
||||
* @param string $msg Message
|
||||
*/
|
||||
public static function head($code, $msg = null)
|
||||
{
|
||||
$status_mode = preg_match('/cgi/', PHP_SAPI);
|
||||
|
||||
if (!$msg) {
|
||||
$msg_codes = [
|
||||
100 => 'Continue',
|
||||
101 => 'Switching Protocols',
|
||||
200 => 'OK',
|
||||
201 => 'Created',
|
||||
202 => 'Accepted',
|
||||
203 => 'Non-Authoritative Information',
|
||||
204 => 'No Content',
|
||||
205 => 'Reset Content',
|
||||
206 => 'Partial Content',
|
||||
300 => 'Multiple Choices',
|
||||
301 => 'Moved Permanently',
|
||||
302 => 'Found',
|
||||
303 => 'See Other',
|
||||
304 => 'Not Modified',
|
||||
305 => 'Use Proxy',
|
||||
307 => 'Temporary Redirect',
|
||||
400 => 'Bad Request',
|
||||
401 => 'Unauthorized',
|
||||
402 => 'Payment Required',
|
||||
403 => 'Forbidden',
|
||||
404 => 'Not Found',
|
||||
405 => 'Method Not Allowed',
|
||||
406 => 'Not Acceptable',
|
||||
407 => 'Proxy Authentication Required',
|
||||
408 => 'Request Timeout',
|
||||
409 => 'Conflict',
|
||||
410 => 'Gone',
|
||||
411 => 'Length Required',
|
||||
412 => 'Precondition Failed',
|
||||
413 => 'Request Entity Too Large',
|
||||
414 => 'Request-URI Too Long',
|
||||
415 => 'Unsupported Media Type',
|
||||
416 => 'Requested Range Not Satisfiable',
|
||||
417 => 'Expectation Failed',
|
||||
500 => 'Internal Server Error',
|
||||
501 => 'Not Implemented',
|
||||
502 => 'Bad Gateway',
|
||||
503 => 'Service Unavailable',
|
||||
504 => 'Gateway Timeout',
|
||||
505 => 'HTTP Version Not Supported'
|
||||
];
|
||||
|
||||
$msg = isset($msg_codes[$code]) ? $msg_codes[$code] : '-';
|
||||
}
|
||||
|
||||
if ($status_mode) {
|
||||
header('Status: ' . $code . ' ' . $msg);
|
||||
} else {
|
||||
header($msg, true, $code);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Trim request
|
||||
*
|
||||
* Trims every value in GET, POST, REQUEST and COOKIE vars.
|
||||
* Removes magic quotes if magic_quote_gpc is on.
|
||||
*/
|
||||
public static function trimRequest()
|
||||
{
|
||||
if (!empty($_GET)) {
|
||||
array_walk($_GET, ['self', 'trimRequestInVar']);
|
||||
}
|
||||
if (!empty($_POST)) {
|
||||
array_walk($_POST, ['self', 'trimRequestInVar']);
|
||||
}
|
||||
if (!empty($_REQUEST)) {
|
||||
array_walk($_REQUEST, ['self', 'trimRequestInVar']);
|
||||
}
|
||||
if (!empty($_COOKIE)) {
|
||||
array_walk($_COOKIE, ['self', 'trimRequestInVar']);
|
||||
}
|
||||
}
|
||||
|
||||
private static function trimRequestInVar(&$value, $key)
|
||||
{
|
||||
if (is_array($value)) {
|
||||
foreach ($value as $k => &$v) {
|
||||
if (is_array($v)) {
|
||||
self::trimRequestInVar($v, $k);
|
||||
} else {
|
||||
$v = trim($v);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$value = trim($value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unset global variables
|
||||
*
|
||||
* If register_globals is on, removes every GET, POST, COOKIE, REQUEST, SERVER,
|
||||
* ENV, FILES vars from GLOBALS.
|
||||
*/
|
||||
public static function unsetGlobals()
|
||||
{
|
||||
if (!ini_get('register_globals')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($_REQUEST['GLOBALS'])) {
|
||||
throw new Exception('GLOBALS overwrite attempt detected');
|
||||
}
|
||||
|
||||
# Variables that shouldn't be unset
|
||||
$no_unset = ['GLOBALS', '_GET', '_POST', '_COOKIE', '_REQUEST',
|
||||
'_SERVER', '_ENV', '_FILES'];
|
||||
|
||||
$input = array_merge(
|
||||
$_GET,
|
||||
$_POST,
|
||||
$_COOKIE,
|
||||
$_SERVER,
|
||||
$_ENV,
|
||||
$_FILES,
|
||||
(isset($_SESSION) && is_array($_SESSION) ? $_SESSION : [])
|
||||
);
|
||||
|
||||
foreach ($input as $k => $v) {
|
||||
if (!in_array($k, $no_unset) && isset($GLOBALS[$k])) {
|
||||
$GLOBALS[$k] = null;
|
||||
unset($GLOBALS[$k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
777
dotclear._no/inc/libs/clearbricks/common/lib.json.php
Normal file
777
dotclear._no/inc/libs/clearbricks/common/lib.json.php
Normal file
@ -0,0 +1,777 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Clearbricks
|
||||
* @subpackage Common
|
||||
*
|
||||
* @copyright Olivier Meunier & Association Dotclear
|
||||
* @copyright GPL-2.0-only
|
||||
*/
|
||||
|
||||
/** @cond ONCE */
|
||||
if (!function_exists('json_encode')) {
|
||||
/** @endcond */
|
||||
|
||||
function json_encode($str)
|
||||
{
|
||||
try {
|
||||
$GLOBALS['json_last_error'] = 0;
|
||||
$json = new Services_JSON();
|
||||
return $json->encode($str);
|
||||
} catch (Exception $e) {
|
||||
$GLOBALS['json_last_error'] = $e->getMessage();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function json_decode($str)
|
||||
{
|
||||
try {
|
||||
$GLOBALS['json_last_error'] = 0;
|
||||
$json = new Services_JSON();
|
||||
return $json->decode($str);
|
||||
} catch (Exception $e) {
|
||||
$GLOBALS['json_last_error'] = $e->getMessage();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function json_last_error()
|
||||
{
|
||||
return empty($GLOBALS['json_last_error']) ? 0 : $GLOBALS['json_last_error'];
|
||||
}
|
||||
|
||||
/** @cond ONCE */
|
||||
}
|
||||
/** @endcond */
|
||||
|
||||
/** @cond ONCE */
|
||||
if (!class_exists('Services_JSON')) {
|
||||
/** @endcond */
|
||||
|
||||
/**
|
||||
* Marker constant for Services_JSON::decode(), used to flag stack state
|
||||
*/
|
||||
define('SERVICES_JSON_SLICE', 1);
|
||||
|
||||
/**
|
||||
* Marker constant for Services_JSON::decode(), used to flag stack state
|
||||
*/
|
||||
define('SERVICES_JSON_IN_STR', 2);
|
||||
|
||||
/**
|
||||
* Marker constant for Services_JSON::decode(), used to flag stack state
|
||||
*/
|
||||
define('SERVICES_JSON_IN_ARR', 3);
|
||||
|
||||
/**
|
||||
* Marker constant for Services_JSON::decode(), used to flag stack state
|
||||
*/
|
||||
define('SERVICES_JSON_IN_OBJ', 4);
|
||||
|
||||
/**
|
||||
* Marker constant for Services_JSON::decode(), used to flag stack state
|
||||
*/
|
||||
define('SERVICES_JSON_IN_CMT', 5);
|
||||
|
||||
/**
|
||||
* Behavior switch for Services_JSON::decode()
|
||||
*/
|
||||
define('SERVICES_JSON_LOOSE_TYPE', 16);
|
||||
|
||||
/**
|
||||
* Behavior switch for Services_JSON::decode()
|
||||
*/
|
||||
define('SERVICES_JSON_SUPPRESS_ERRORS', 32);
|
||||
|
||||
/**
|
||||
* @class Services_JSON
|
||||
* @brief Converts to and from JSON format.
|
||||
*
|
||||
* This class library is from Michal Migurski's Services_JSON library (http://pear.php.net/pepr/pepr-proposal-show.php?id=198 <a href="http://www.opensource.org/licenses/bsd-license.php">BSD</a>)
|
||||
*
|
||||
* @package Clearbricks
|
||||
* @subpackage Common
|
||||
*/
|
||||
class Services_JSON
|
||||
{
|
||||
/**
|
||||
* constructs a new JSON instance
|
||||
*
|
||||
* @param int $use object behavior flags; combine with boolean-OR
|
||||
*
|
||||
* possible values:
|
||||
* - SERVICES_JSON_LOOSE_TYPE: loose typing.
|
||||
* "{...}" syntax creates associative arrays
|
||||
* instead of objects in decode().
|
||||
* - SERVICES_JSON_SUPPRESS_ERRORS: error suppression.
|
||||
* Values which can't be encoded (e.g. resources)
|
||||
* appear as NULL instead of throwing errors.
|
||||
* By default, a deeply-nested resource will
|
||||
* bubble up with an error, so all return values
|
||||
* from encode() should be checked with isError()
|
||||
*/
|
||||
public function __construct($use = 0)
|
||||
{
|
||||
$this->use = $use;
|
||||
}
|
||||
|
||||
/**
|
||||
* convert a string from one UTF-16 char to one UTF-8 char
|
||||
*
|
||||
* Normally should be handled by mb_convert_encoding, but
|
||||
* provides a slower PHP-only method for installations
|
||||
* that lack the multibye string extension.
|
||||
*
|
||||
* @param string $utf16 UTF-16 character
|
||||
* @return string UTF-8 character
|
||||
*/
|
||||
public function utf162utf8($utf16)
|
||||
{
|
||||
// oh please oh please oh please oh please oh please
|
||||
if (function_exists('mb_convert_encoding')) {
|
||||
return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16');
|
||||
}
|
||||
|
||||
$bytes = (ord($utf16[0]) << 8) | ord($utf16[1]);
|
||||
|
||||
switch (true) {
|
||||
case ((0x7F & $bytes) == $bytes):
|
||||
// this case should never be reached, because we are in ASCII range
|
||||
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
||||
return chr(0x7F & $bytes);
|
||||
|
||||
case (0x07FF & $bytes) == $bytes:
|
||||
// return a 2-byte UTF-8 character
|
||||
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
||||
return chr(0xC0 | (($bytes >> 6) & 0x1F))
|
||||
. chr(0x80 | ($bytes & 0x3F));
|
||||
|
||||
case (0xFFFF & $bytes) == $bytes:
|
||||
// return a 3-byte UTF-8 character
|
||||
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
||||
return chr(0xE0 | (($bytes >> 12) & 0x0F))
|
||||
. chr(0x80 | (($bytes >> 6) & 0x3F))
|
||||
. chr(0x80 | ($bytes & 0x3F));
|
||||
}
|
||||
|
||||
// ignoring UTF-32 for now, sorry
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* convert a string from one UTF-8 char to one UTF-16 char
|
||||
*
|
||||
* Normally should be handled by mb_convert_encoding, but
|
||||
* provides a slower PHP-only method for installations
|
||||
* that lack the multibye string extension.
|
||||
*
|
||||
* @param string $utf8 UTF-8 character
|
||||
* @return string UTF-16 character
|
||||
*/
|
||||
public function utf82utf16($utf8)
|
||||
{
|
||||
// oh please oh please oh please oh please oh please
|
||||
if (function_exists('mb_convert_encoding')) {
|
||||
return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8');
|
||||
}
|
||||
|
||||
switch (strlen($utf8)) {
|
||||
case 1:
|
||||
// this case should never be reached, because we are in ASCII range
|
||||
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
||||
return $utf8;
|
||||
|
||||
case 2:
|
||||
// return a UTF-16 character from a 2-byte UTF-8 char
|
||||
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
||||
return chr(0x07 & (ord($utf8[0]) >> 2))
|
||||
. chr((0xC0 & (ord($utf8[0]) << 6))
|
||||
| (0x3F & ord($utf8[1])));
|
||||
|
||||
case 3:
|
||||
// return a UTF-16 character from a 3-byte UTF-8 char
|
||||
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
||||
return chr((0xF0 & (ord($utf8[0]) << 4))
|
||||
| (0x0F & (ord($utf8[1]) >> 2)))
|
||||
. chr((0xC0 & (ord($utf8[1]) << 6))
|
||||
| (0x7F & ord($utf8[2])));
|
||||
}
|
||||
|
||||
// ignoring UTF-32 for now, sorry
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* encodes an arbitrary variable into JSON format
|
||||
*
|
||||
* @param mixed $var any number, boolean, string, array, or object to be encoded.
|
||||
* see argument 1 to Services_JSON() above for array-parsing behavior.
|
||||
* if var is a strng, note that encode() always expects it
|
||||
* to be in ASCII or UTF-8 format!
|
||||
*
|
||||
* @return mixed JSON string representation of input var or an error if a problem occurs
|
||||
*/
|
||||
public function encode($var)
|
||||
{
|
||||
switch (gettype($var)) {
|
||||
case 'boolean':
|
||||
return $var ? 'true' : 'false';
|
||||
|
||||
case 'NULL':
|
||||
return 'null';
|
||||
|
||||
case 'integer':
|
||||
return (int) $var;
|
||||
|
||||
case 'double':
|
||||
case 'float':
|
||||
return (float) $var;
|
||||
|
||||
case 'string':
|
||||
// STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT
|
||||
$ascii = '';
|
||||
$strlen_var = strlen($var);
|
||||
|
||||
/*
|
||||
* Iterate over every character in the string,
|
||||
* escaping with a slash or encoding to UTF-8 where necessary
|
||||
*/
|
||||
for ($c = 0; $c < $strlen_var; ++$c) {
|
||||
|
||||
$ord_var_c = ord($var[$c]);
|
||||
|
||||
switch (true) {
|
||||
case $ord_var_c == 0x08:
|
||||
$ascii .= '\b';
|
||||
break;
|
||||
case $ord_var_c == 0x09:
|
||||
$ascii .= '\t';
|
||||
break;
|
||||
case $ord_var_c == 0x0A:
|
||||
$ascii .= '\n';
|
||||
break;
|
||||
case $ord_var_c == 0x0C:
|
||||
$ascii .= '\f';
|
||||
break;
|
||||
case $ord_var_c == 0x0D:
|
||||
$ascii .= '\r';
|
||||
break;
|
||||
|
||||
case $ord_var_c == 0x22:
|
||||
case $ord_var_c == 0x2F:
|
||||
case $ord_var_c == 0x5C:
|
||||
// double quote, slash, slosh
|
||||
$ascii .= '\\' . $var[$c];
|
||||
break;
|
||||
|
||||
case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)):
|
||||
// characters U-00000000 - U-0000007F (same as ASCII)
|
||||
$ascii .= $var[$c];
|
||||
break;
|
||||
|
||||
case (($ord_var_c & 0xE0) == 0xC0):
|
||||
// characters U-00000080 - U-000007FF, mask 110XXXXX
|
||||
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
||||
$char = pack('C*', $ord_var_c, ord($var[$c + 1]));
|
||||
$c += 1;
|
||||
$utf16 = $this->utf82utf16($char);
|
||||
$ascii .= sprintf('\u%04s', bin2hex($utf16));
|
||||
break;
|
||||
|
||||
case (($ord_var_c & 0xF0) == 0xE0):
|
||||
// characters U-00000800 - U-0000FFFF, mask 1110XXXX
|
||||
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
||||
$char = pack('C*', $ord_var_c,
|
||||
ord($var[$c + 1]),
|
||||
ord($var[$c + 2]));
|
||||
$c += 2;
|
||||
$utf16 = $this->utf82utf16($char);
|
||||
$ascii .= sprintf('\u%04s', bin2hex($utf16));
|
||||
break;
|
||||
|
||||
case (($ord_var_c & 0xF8) == 0xF0):
|
||||
// characters U-00010000 - U-001FFFFF, mask 11110XXX
|
||||
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
||||
$char = pack('C*', $ord_var_c,
|
||||
ord($var[$c + 1]),
|
||||
ord($var[$c + 2]),
|
||||
ord($var[$c + 3]));
|
||||
$c += 3;
|
||||
$utf16 = $this->utf82utf16($char);
|
||||
$ascii .= sprintf('\u%04s', bin2hex($utf16));
|
||||
break;
|
||||
|
||||
case (($ord_var_c & 0xFC) == 0xF8):
|
||||
// characters U-00200000 - U-03FFFFFF, mask 111110XX
|
||||
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
||||
$char = pack('C*', $ord_var_c,
|
||||
ord($var[$c + 1]),
|
||||
ord($var[$c + 2]),
|
||||
ord($var[$c + 3]),
|
||||
ord($var[$c + 4]));
|
||||
$c += 4;
|
||||
$utf16 = $this->utf82utf16($char);
|
||||
$ascii .= sprintf('\u%04s', bin2hex($utf16));
|
||||
break;
|
||||
|
||||
case (($ord_var_c & 0xFE) == 0xFC):
|
||||
// characters U-04000000 - U-7FFFFFFF, mask 1111110X
|
||||
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
||||
$char = pack('C*', $ord_var_c,
|
||||
ord($var[$c + 1]),
|
||||
ord($var[$c + 2]),
|
||||
ord($var[$c + 3]),
|
||||
ord($var[$c + 4]),
|
||||
ord($var[$c + 5]));
|
||||
$c += 5;
|
||||
$utf16 = $this->utf82utf16($char);
|
||||
$ascii .= sprintf('\u%04s', bin2hex($utf16));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return '"' . $ascii . '"';
|
||||
|
||||
case 'array':
|
||||
/*
|
||||
* As per JSON spec if any array key is not an integer
|
||||
* we must treat the the whole array as an object. We
|
||||
* also try to catch a sparsely populated associative
|
||||
* array with numeric keys here because some JS engines
|
||||
* will create an array with empty indexes up to
|
||||
* max_index which can cause memory issues and because
|
||||
* the keys, which may be relevant, will be remapped
|
||||
* otherwise.
|
||||
*
|
||||
* As per the ECMA and JSON specification an object may
|
||||
* have any string as a property. Unfortunately due to
|
||||
* a hole in the ECMA specification if the key is a
|
||||
* ECMA reserved word or starts with a digit the
|
||||
* parameter is only accessible using ECMAScript's
|
||||
* bracket notation.
|
||||
*/
|
||||
|
||||
// treat as a JSON object
|
||||
if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) {
|
||||
$properties = array_map([$this, 'name_value'],
|
||||
array_keys($var),
|
||||
array_values($var));
|
||||
|
||||
foreach ($properties as $property) {
|
||||
if (Services_JSON::isError($property)) {
|
||||
return $property;
|
||||
}
|
||||
}
|
||||
|
||||
return '{' . join(',', $properties) . '}';
|
||||
}
|
||||
|
||||
// treat it like a regular array
|
||||
$elements = array_map([$this, 'encode'], $var);
|
||||
|
||||
foreach ($elements as $element) {
|
||||
if (Services_JSON::isError($element)) {
|
||||
return $element;
|
||||
}
|
||||
}
|
||||
|
||||
return '[' . join(',', $elements) . ']';
|
||||
|
||||
case 'object':
|
||||
$vars = get_object_vars($var);
|
||||
|
||||
$properties = array_map([$this, 'name_value'],
|
||||
array_keys($vars),
|
||||
array_values($vars));
|
||||
|
||||
foreach ($properties as $property) {
|
||||
if (Services_JSON::isError($property)) {
|
||||
return $property;
|
||||
}
|
||||
}
|
||||
|
||||
return '{' . join(',', $properties) . '}';
|
||||
|
||||
default:
|
||||
return ($this->use & SERVICES_JSON_SUPPRESS_ERRORS)
|
||||
? 'null'
|
||||
: new Services_JSON_Error(gettype($var) . " can not be encoded as JSON string");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* array-walking function for use in generating JSON-formatted name-value pairs
|
||||
*
|
||||
* @param string $name name of key to use
|
||||
* @param mixed $value reference to an array element to be encoded
|
||||
*
|
||||
* @return string JSON-formatted name-value pair, like '"name":value'
|
||||
*/
|
||||
public function name_value($name, $value)
|
||||
{
|
||||
$encoded_value = $this->encode($value);
|
||||
|
||||
if (Services_JSON::isError($encoded_value)) {
|
||||
return $encoded_value;
|
||||
}
|
||||
|
||||
return $this->encode(strval($name)) . ':' . $encoded_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* reduce a string by removing leading and trailing comments and whitespace
|
||||
*
|
||||
* @param $str string string value to strip of comments and whitespace
|
||||
*
|
||||
* @return string string value stripped of comments and whitespace
|
||||
*/
|
||||
public function reduce_string($str)
|
||||
{
|
||||
$str = preg_replace([
|
||||
|
||||
// eliminate single line comments in '// ...' form
|
||||
'#^\s*//(.+)$#m',
|
||||
|
||||
// eliminate multi-line comments in '/* ... */' form, at start of string
|
||||
'#^\s*/\*(.+)\*/#Us',
|
||||
|
||||
// eliminate multi-line comments in '/* ... */' form, at end of string
|
||||
'#/\*(.+)\*/\s*$#Us'
|
||||
|
||||
], '', $str);
|
||||
|
||||
// eliminate extraneous space
|
||||
return trim($str);
|
||||
}
|
||||
|
||||
/**
|
||||
* decodes a JSON string into appropriate variable
|
||||
*
|
||||
* @param string $str JSON-formatted string
|
||||
*
|
||||
* @return mixed number, boolean, string, array, or object
|
||||
* corresponding to given JSON input string.
|
||||
* See argument 1 to Services_JSON() above for object-output behavior.
|
||||
* Note that decode() always returns strings
|
||||
* in ASCII or UTF-8 format!
|
||||
*/
|
||||
public function decode($str)
|
||||
{
|
||||
$str = $this->reduce_string($str);
|
||||
|
||||
switch (strtolower($str)) {
|
||||
case 'true':
|
||||
return true;
|
||||
|
||||
case 'false':
|
||||
return false;
|
||||
|
||||
case 'null':
|
||||
return;
|
||||
|
||||
default:
|
||||
$m = [];
|
||||
|
||||
if (is_numeric($str)) {
|
||||
// Lookie-loo, it's a number
|
||||
|
||||
// This would work on its own, but I'm trying to be
|
||||
// good about returning integers where appropriate:
|
||||
// return (float)$str;
|
||||
|
||||
// Return float or int, as appropriate
|
||||
return ((float) $str == (integer) $str)
|
||||
? (integer) $str
|
||||
: (float) $str;
|
||||
|
||||
} elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) {
|
||||
// STRINGS RETURNED IN UTF-8 FORMAT
|
||||
$delim = substr($str, 0, 1);
|
||||
$chrs = substr($str, 1, -1);
|
||||
$utf8 = '';
|
||||
$strlen_chrs = strlen($chrs);
|
||||
|
||||
for ($c = 0; $c < $strlen_chrs; ++$c) {
|
||||
|
||||
$substr_chrs_c_2 = substr($chrs, $c, 2);
|
||||
$ord_chrs_c = ord($chrs[$c]);
|
||||
|
||||
switch (true) {
|
||||
case $substr_chrs_c_2 == '\b':
|
||||
$utf8 .= chr(0x08);
|
||||
++$c;
|
||||
break;
|
||||
case $substr_chrs_c_2 == '\t':
|
||||
$utf8 .= chr(0x09);
|
||||
++$c;
|
||||
break;
|
||||
case $substr_chrs_c_2 == '\n':
|
||||
$utf8 .= chr(0x0A);
|
||||
++$c;
|
||||
break;
|
||||
case $substr_chrs_c_2 == '\f':
|
||||
$utf8 .= chr(0x0C);
|
||||
++$c;
|
||||
break;
|
||||
case $substr_chrs_c_2 == '\r':
|
||||
$utf8 .= chr(0x0D);
|
||||
++$c;
|
||||
break;
|
||||
|
||||
case $substr_chrs_c_2 == '\\"':
|
||||
case $substr_chrs_c_2 == '\\\'':
|
||||
case $substr_chrs_c_2 == '\\\\':
|
||||
case $substr_chrs_c_2 == '\\/':
|
||||
if (($delim == '"' && $substr_chrs_c_2 != '\\\'') ||
|
||||
($delim == "'" && $substr_chrs_c_2 != '\\"')) {
|
||||
$utf8 .= $chrs[ ++$c];
|
||||
}
|
||||
break;
|
||||
|
||||
case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)):
|
||||
// single, escaped unicode character
|
||||
$utf16 = chr(hexdec(substr($chrs, ($c + 2), 2)))
|
||||
. chr(hexdec(substr($chrs, ($c + 4), 2)));
|
||||
$utf8 .= $this->utf162utf8($utf16);
|
||||
$c += 5;
|
||||
break;
|
||||
|
||||
case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F):
|
||||
$utf8 .= $chrs[$c];
|
||||
break;
|
||||
|
||||
case ($ord_chrs_c & 0xE0) == 0xC0:
|
||||
// characters U-00000080 - U-000007FF, mask 110XXXXX
|
||||
//see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
||||
$utf8 .= substr($chrs, $c, 2);
|
||||
++$c;
|
||||
break;
|
||||
|
||||
case ($ord_chrs_c & 0xF0) == 0xE0:
|
||||
// characters U-00000800 - U-0000FFFF, mask 1110XXXX
|
||||
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
||||
$utf8 .= substr($chrs, $c, 3);
|
||||
$c += 2;
|
||||
break;
|
||||
|
||||
case ($ord_chrs_c & 0xF8) == 0xF0:
|
||||
// characters U-00010000 - U-001FFFFF, mask 11110XXX
|
||||
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
||||
$utf8 .= substr($chrs, $c, 4);
|
||||
$c += 3;
|
||||
break;
|
||||
|
||||
case ($ord_chrs_c & 0xFC) == 0xF8:
|
||||
// characters U-00200000 - U-03FFFFFF, mask 111110XX
|
||||
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
||||
$utf8 .= substr($chrs, $c, 5);
|
||||
$c += 4;
|
||||
break;
|
||||
|
||||
case ($ord_chrs_c & 0xFE) == 0xFC:
|
||||
// characters U-04000000 - U-7FFFFFFF, mask 1111110X
|
||||
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
||||
$utf8 .= substr($chrs, $c, 6);
|
||||
$c += 5;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $utf8;
|
||||
|
||||
} elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) {
|
||||
// array, or object notation
|
||||
|
||||
if ($str[0] == '[') {
|
||||
$stk = [SERVICES_JSON_IN_ARR];
|
||||
$arr = [];
|
||||
} else {
|
||||
if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
|
||||
$stk = [SERVICES_JSON_IN_OBJ];
|
||||
$obj = [];
|
||||
} else {
|
||||
$stk = [SERVICES_JSON_IN_OBJ];
|
||||
$obj = new stdClass();
|
||||
}
|
||||
}
|
||||
|
||||
array_push($stk, ['what' => SERVICES_JSON_SLICE,
|
||||
'where' => 0,
|
||||
'delim' => false]);
|
||||
|
||||
$chrs = substr($str, 1, -1);
|
||||
$chrs = $this->reduce_string($chrs);
|
||||
|
||||
if ($chrs == '') {
|
||||
if (reset($stk) == SERVICES_JSON_IN_ARR) {
|
||||
return $arr;
|
||||
|
||||
} else {
|
||||
return $obj;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//print("\nparsing {$chrs}\n");
|
||||
|
||||
$strlen_chrs = strlen($chrs);
|
||||
|
||||
for ($c = 0; $c <= $strlen_chrs; ++$c) {
|
||||
|
||||
$top = end($stk);
|
||||
$substr_chrs_c_2 = substr($chrs, $c, 2);
|
||||
|
||||
if (($c == $strlen_chrs) || (($chrs[$c] == ',') && ($top['what'] == SERVICES_JSON_SLICE))) {
|
||||
// found a comma that is not inside a string, array, etc.,
|
||||
// OR we've reached the end of the character list
|
||||
$slice = substr($chrs, $top['where'], ($c - $top['where']));
|
||||
array_push($stk, ['what' => SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false]);
|
||||
//print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
|
||||
|
||||
if (reset($stk) == SERVICES_JSON_IN_ARR) {
|
||||
// we are in an array, so just push an element onto the stack
|
||||
array_push($arr, $this->decode($slice));
|
||||
|
||||
} elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
|
||||
// we are in an object, so figure
|
||||
// out the property name and set an
|
||||
// element in an associative array,
|
||||
// for now
|
||||
$parts = [];
|
||||
|
||||
if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
|
||||
// "name":value pair
|
||||
$key = $this->decode($parts[1]);
|
||||
$val = $this->decode($parts[2]);
|
||||
|
||||
if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
|
||||
$obj[$key] = $val;
|
||||
} else {
|
||||
$obj->$key = $val;
|
||||
}
|
||||
} elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
|
||||
// name:value pair, where name is unquoted
|
||||
$key = $parts[1];
|
||||
$val = $this->decode($parts[2]);
|
||||
|
||||
if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
|
||||
$obj[$key] = $val;
|
||||
} else {
|
||||
$obj->$key = $val;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} elseif ((($chrs[$c] == '"') || ($chrs[$c] == "'")) && ($top['what'] != SERVICES_JSON_IN_STR)) {
|
||||
// found a quote, and we are not inside a string
|
||||
array_push($stk, ['what' => SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs[$c]]);
|
||||
//print("Found start of string at {$c}\n");
|
||||
|
||||
} elseif (($chrs[$c] == $top['delim']) &&
|
||||
($top['what'] == SERVICES_JSON_IN_STR) &&
|
||||
((strlen(substr($chrs, 0, $c)) - strlen(rtrim(substr($chrs, 0, $c), '\\'))) % 2 != 1)) {
|
||||
// found a quote, we're in a string, and it's not escaped
|
||||
// we know that it's not escaped becase there is _not_ an
|
||||
// odd number of backslashes at the end of the string so far
|
||||
array_pop($stk);
|
||||
//print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n");
|
||||
|
||||
} elseif (($chrs[$c] == '[') &&
|
||||
in_array($top['what'], [SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ])) {
|
||||
// found a left-bracket, and we are in an array, object, or slice
|
||||
array_push($stk, ['what' => SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false]);
|
||||
//print("Found start of array at {$c}\n");
|
||||
|
||||
} elseif (($chrs[$c] == ']') && ($top['what'] == SERVICES_JSON_IN_ARR)) {
|
||||
// found a right-bracket, and we're in an array
|
||||
array_pop($stk);
|
||||
//print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
|
||||
|
||||
} elseif (($chrs[$c] == '{') &&
|
||||
in_array($top['what'], [SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ])) {
|
||||
// found a left-brace, and we are in an array, object, or slice
|
||||
array_push($stk, ['what' => SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false]);
|
||||
//print("Found start of object at {$c}\n");
|
||||
|
||||
} elseif (($chrs[$c] == '}') && ($top['what'] == SERVICES_JSON_IN_OBJ)) {
|
||||
// found a right-brace, and we're in an object
|
||||
array_pop($stk);
|
||||
//print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
|
||||
|
||||
} elseif (($substr_chrs_c_2 == '/*') &&
|
||||
in_array($top['what'], [SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ])) {
|
||||
// found a comment start, and we are in an array, object, or slice
|
||||
array_push($stk, ['what' => SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false]);
|
||||
$c++;
|
||||
//print("Found start of comment at {$c}\n");
|
||||
|
||||
} elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == SERVICES_JSON_IN_CMT)) {
|
||||
// found a comment end, and we're in one now
|
||||
array_pop($stk);
|
||||
$c++;
|
||||
|
||||
for ($i = $top['where']; $i <= $c; ++$i) {
|
||||
$chrs = substr_replace($chrs, ' ', $i, 1);
|
||||
}
|
||||
|
||||
//print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (reset($stk) == SERVICES_JSON_IN_ARR) {
|
||||
return $arr;
|
||||
|
||||
} elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
|
||||
return $obj;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function isError($data, $code = null)
|
||||
{
|
||||
if (class_exists('pear')) {
|
||||
return PEAR::isError($data, $code);
|
||||
} elseif (is_object($data) && (get_class($data) == 'services_json_error' ||
|
||||
is_subclass_of($data, 'services_json_error'))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/** @cond ONCE */
|
||||
if (class_exists('PEAR_Error')) {
|
||||
/** @endcond */
|
||||
|
||||
class Services_JSON_Error extends PEAR_Error
|
||||
{
|
||||
public function __construct($message = 'unknown error', $code = null,
|
||||
$mode = null, $options = null, $userinfo = null) {
|
||||
parent::PEAR_Error($message, $code, $mode, $options, $userinfo);
|
||||
}
|
||||
}
|
||||
|
||||
/** @cond ONCE */
|
||||
} else {
|
||||
class Services_JSON_Error
|
||||
{
|
||||
public function __construct($message = 'unknown error', $code = null,
|
||||
$mode = null, $options = null, $userinfo = null) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
/** @endcond */
|
||||
|
||||
/** @cond ONCE */
|
||||
}
|
||||
/** @endcond */
|
||||
1098
dotclear._no/inc/libs/clearbricks/common/lib.l10n.php
Normal file
1098
dotclear._no/inc/libs/clearbricks/common/lib.l10n.php
Normal file
File diff suppressed because it is too large
Load Diff
324
dotclear._no/inc/libs/clearbricks/common/lib.text.php
Normal file
324
dotclear._no/inc/libs/clearbricks/common/lib.text.php
Normal file
@ -0,0 +1,324 @@
|
||||
<?php
|
||||
/**
|
||||
* @class text
|
||||
* @brief Text utilities
|
||||
*
|
||||
* @package Clearbricks
|
||||
* @subpackage Common
|
||||
*
|
||||
* @copyright Olivier Meunier & Association Dotclear
|
||||
* @copyright GPL-2.0-only
|
||||
*/
|
||||
|
||||
class text
|
||||
{
|
||||
/**
|
||||
* Check email address
|
||||
*
|
||||
* Returns true if $email is a valid email address.
|
||||
*
|
||||
* @param string $email Email string
|
||||
* @return boolean
|
||||
*/
|
||||
public static function isEmail($email)
|
||||
{
|
||||
return (filter_var($email, FILTER_VALIDATE_EMAIL) !== false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Accents replacement
|
||||
*
|
||||
* Replaces some occidental accentuated characters by their ASCII
|
||||
* representation.
|
||||
*
|
||||
* @param string $str String to deaccent
|
||||
* @return string
|
||||
*/
|
||||
public static function deaccent($str)
|
||||
{
|
||||
$pattern['A'] = '\x{00C0}-\x{00C5}';
|
||||
$pattern['AE'] = '\x{00C6}';
|
||||
$pattern['C'] = '\x{00C7}';
|
||||
$pattern['D'] = '\x{00D0}';
|
||||
$pattern['E'] = '\x{00C8}-\x{00CB}';
|
||||
$pattern['I'] = '\x{00CC}-\x{00CF}';
|
||||
$pattern['N'] = '\x{00D1}';
|
||||
$pattern['O'] = '\x{00D2}-\x{00D6}\x{00D8}';
|
||||
$pattern['OE'] = '\x{0152}';
|
||||
$pattern['S'] = '\x{0160}';
|
||||
$pattern['U'] = '\x{00D9}-\x{00DC}';
|
||||
$pattern['Y'] = '\x{00DD}';
|
||||
$pattern['Z'] = '\x{017D}';
|
||||
|
||||
$pattern['a'] = '\x{00E0}-\x{00E5}';
|
||||
$pattern['ae'] = '\x{00E6}';
|
||||
$pattern['c'] = '\x{00E7}';
|
||||
$pattern['d'] = '\x{00F0}';
|
||||
$pattern['e'] = '\x{00E8}-\x{00EB}';
|
||||
$pattern['i'] = '\x{00EC}-\x{00EF}';
|
||||
$pattern['n'] = '\x{00F1}';
|
||||
$pattern['o'] = '\x{00F2}-\x{00F6}\x{00F8}';
|
||||
$pattern['oe'] = '\x{0153}';
|
||||
$pattern['s'] = '\x{0161}';
|
||||
$pattern['u'] = '\x{00F9}-\x{00FC}';
|
||||
$pattern['y'] = '\x{00FD}\x{00FF}';
|
||||
$pattern['z'] = '\x{017E}';
|
||||
|
||||
$pattern['ss'] = '\x{00DF}';
|
||||
|
||||
foreach ($pattern as $r => $p) {
|
||||
$str = preg_replace('/[' . $p . ']/u', $r, $str);
|
||||
}
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* String to URL
|
||||
*
|
||||
* Transforms a string to a proper URL.
|
||||
*
|
||||
* @param string $str String to transform
|
||||
* @param boolean $with_slashes Keep slashes in URL
|
||||
* @return string
|
||||
*/
|
||||
public static function str2URL($str, $with_slashes = true)
|
||||
{
|
||||
$str = self::deaccent($str);
|
||||
$str = preg_replace('/[^A-Za-z0-9_\s\'\:\/[\]-]/', '', $str);
|
||||
|
||||
return self::tidyURL($str, $with_slashes);
|
||||
}
|
||||
|
||||
/**
|
||||
* URL cleanup
|
||||
*
|
||||
* @param string $str URL to tidy
|
||||
* @param boolean $keep_slashes Keep slashes in URL
|
||||
* @param boolean $keep_spaces Keep spaces in URL
|
||||
* @return string
|
||||
*/
|
||||
public static function tidyURL($str, $keep_slashes = true, $keep_spaces = false)
|
||||
{
|
||||
$str = strip_tags($str);
|
||||
$str = str_replace(['?', '&', '#', '=', '+', '<', '>', '"', '%'], '', $str);
|
||||
$str = str_replace("'", ' ', $str);
|
||||
$str = preg_replace('/[\s]+/u', ' ', trim($str));
|
||||
|
||||
if (!$keep_slashes) {
|
||||
$str = str_replace('/', '-', $str);
|
||||
}
|
||||
|
||||
if (!$keep_spaces) {
|
||||
$str = str_replace(' ', '-', $str);
|
||||
}
|
||||
|
||||
$str = preg_replace('/[-]+/', '-', $str);
|
||||
|
||||
# Remove path changes in URL
|
||||
$str = preg_replace('%^/%', '', $str);
|
||||
$str = preg_replace('%\.+/%', '', $str);
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cut string
|
||||
*
|
||||
* Returns a cuted string on spaced at given length $l.
|
||||
*
|
||||
* @param string $str String to cut
|
||||
* @param integer $l Length to keep
|
||||
* @return string
|
||||
*/
|
||||
public static function cutString($str, $l)
|
||||
{
|
||||
$s = preg_split('/([\s]+)/u', $str, -1, PREG_SPLIT_DELIM_CAPTURE);
|
||||
|
||||
$res = '';
|
||||
$L = 0;
|
||||
|
||||
if (mb_strlen($s[0]) >= $l) {
|
||||
return mb_substr($s[0], 0, $l);
|
||||
}
|
||||
|
||||
foreach ($s as $v) {
|
||||
$L = $L + mb_strlen($v);
|
||||
|
||||
if ($L > $l) {
|
||||
break;
|
||||
} else {
|
||||
$res .= $v;
|
||||
}
|
||||
}
|
||||
|
||||
return trim($res);
|
||||
}
|
||||
|
||||
/**
|
||||
* Split words
|
||||
*
|
||||
* Returns an array of words from a given string.
|
||||
*
|
||||
* @param string $str Words to split
|
||||
* @return array
|
||||
*/
|
||||
public static function splitWords($str)
|
||||
{
|
||||
$non_word = '\x{0000}-\x{002F}\x{003A}-\x{0040}\x{005b}-\x{0060}\x{007B}-\x{007E}\x{00A0}-\x{00BF}\s';
|
||||
if (preg_match_all('/([^' . $non_word . ']{3,})/msu', html::clean($str), $match)) {
|
||||
foreach ($match[1] as $i => $v) {
|
||||
$match[1][$i] = mb_strtolower($v);
|
||||
}
|
||||
return $match[1];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Encoding detection
|
||||
*
|
||||
* Returns the encoding (in lowercase) of given $str.
|
||||
*
|
||||
* @param string $str String
|
||||
* @return string
|
||||
*/
|
||||
public static function detectEncoding($str)
|
||||
{
|
||||
return strtolower(mb_detect_encoding($str . ' ',
|
||||
'UTF-8,ISO-8859-1,ISO-8859-2,ISO-8859-3,' .
|
||||
'ISO-8859-4,ISO-8859-5,ISO-8859-6,ISO-8859-7,ISO-8859-8,' .
|
||||
'ISO-8859-9,ISO-8859-10,ISO-8859-13,ISO-8859-14,ISO-8859-15'));
|
||||
}
|
||||
|
||||
/**
|
||||
* UTF8 conversions
|
||||
*
|
||||
* Returns an UTF-8 converted string. If $encoding is not specified, the
|
||||
* function will try to detect encoding.
|
||||
*
|
||||
* @param string $str String to convert
|
||||
* @param string $encoding Optionnal "from" encoding
|
||||
* @return string
|
||||
*/
|
||||
public static function toUTF8($str, $encoding = null)
|
||||
{
|
||||
if (!$encoding) {
|
||||
$encoding = self::detectEncoding($str);
|
||||
}
|
||||
|
||||
if ($encoding != 'utf-8') {
|
||||
$str = iconv($encoding, 'UTF-8', $str);
|
||||
}
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find bad UTF8 tokens
|
||||
*
|
||||
* Locates the first bad byte in a UTF-8 string returning it's
|
||||
* byte index in the string
|
||||
* PCRE Pattern to locate bad bytes in a UTF-8 string
|
||||
* Comes from W3 FAQ: Multilingual Forms
|
||||
* Note: modified to include full ASCII range including control chars
|
||||
*
|
||||
* @copyright Harry Fuecks (http://phputf8.sourceforge.net <a href="http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html">GNU LGPL 2.1</a>)
|
||||
*
|
||||
* @param string $str String to search
|
||||
* @return integer|false
|
||||
*/
|
||||
public static function utf8badFind($str)
|
||||
{
|
||||
$UTF8_BAD =
|
||||
'([\x00-\x7F]' . # ASCII (including control chars)
|
||||
'|[\xC2-\xDF][\x80-\xBF]' . # non-overlong 2-byte
|
||||
'|\xE0[\xA0-\xBF][\x80-\xBF]' . # excluding overlongs
|
||||
'|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}' . # straight 3-byte
|
||||
'|\xED[\x80-\x9F][\x80-\xBF]' . # excluding surrogates
|
||||
'|\xF0[\x90-\xBF][\x80-\xBF]{2}' . # planes 1-3
|
||||
'|[\xF1-\xF3][\x80-\xBF]{3}' . # planes 4-15
|
||||
'|\xF4[\x80-\x8F][\x80-\xBF]{2}' . # plane 16
|
||||
'|(.{1}))'; # invalid byte
|
||||
$pos = 0;
|
||||
$badList = [];
|
||||
|
||||
while (preg_match('/' . $UTF8_BAD . '/S', $str, $matches)) {
|
||||
$bytes = strlen($matches[0]);
|
||||
if (isset($matches[2])) {
|
||||
return $pos;
|
||||
}
|
||||
$pos += $bytes;
|
||||
$str = substr($str, $bytes);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* UTF8 cleanup
|
||||
*
|
||||
* Replaces non utf8 bytes in $str by $repl.
|
||||
*
|
||||
* @copyright Harry Fuecks (http://phputf8.sourceforge.net <a href="http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html">GNU LGPL 2.1</a>)
|
||||
*
|
||||
* @param string $str String to clean
|
||||
* @param string $repl Replacement string
|
||||
* @return string
|
||||
*/
|
||||
public static function cleanUTF8($str, $repl = '?')
|
||||
{
|
||||
while (($bad_index = self::utf8badFind($str)) !== false) {
|
||||
$str = substr_replace($str, $repl, $bad_index, 1);
|
||||
}
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* BOM removal
|
||||
*
|
||||
* Removes BOM from the begining of a string if present.
|
||||
*
|
||||
* @param string $str String to clean
|
||||
* @return string
|
||||
*/
|
||||
public static function removeBOM($str)
|
||||
{
|
||||
if (substr_count($str, '')) {
|
||||
return str_replace('', '', $str);
|
||||
}
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Quoted printable conversion
|
||||
*
|
||||
* Encodes given str to quoted printable
|
||||
*
|
||||
* @param string $str String to encode
|
||||
* @return string
|
||||
*/
|
||||
public static function QPEncode($str)
|
||||
{
|
||||
$res = '';
|
||||
|
||||
foreach (preg_split("/\r?\n/msu", $str) as $line) {
|
||||
$l = '';
|
||||
preg_match_all('/./', $line, $m);
|
||||
|
||||
foreach ($m[0] as $c) {
|
||||
$a = ord($c);
|
||||
|
||||
if ($a < 32 || $a == 61 || $a > 126) {
|
||||
$c = sprintf('=%02X', $a);
|
||||
}
|
||||
|
||||
$l .= $c;
|
||||
}
|
||||
|
||||
$res .= $l . "\r\n";
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
}
|
||||
407
dotclear._no/inc/libs/clearbricks/common/tz.dat
Normal file
407
dotclear._no/inc/libs/clearbricks/common/tz.dat
Normal file
@ -0,0 +1,407 @@
|
||||
Africa/Abidjan
|
||||
Africa/Accra
|
||||
Africa/Addis_Ababa
|
||||
Africa/Algiers
|
||||
Africa/Asmera
|
||||
Africa/Bamako
|
||||
Africa/Bangui
|
||||
Africa/Banjul
|
||||
Africa/Bissau
|
||||
Africa/Blantyre
|
||||
Africa/Brazzaville
|
||||
Africa/Bujumbura
|
||||
Africa/Cairo
|
||||
Africa/Casablanca
|
||||
Africa/Ceuta
|
||||
Africa/Conakry
|
||||
Africa/Dakar
|
||||
Africa/Dar_es_Salaam
|
||||
Africa/Djibouti
|
||||
Africa/Douala
|
||||
Africa/El_Aaiun
|
||||
Africa/Freetown
|
||||
Africa/Gaborone
|
||||
Africa/Harare
|
||||
Africa/Johannesburg
|
||||
Africa/Kampala
|
||||
Africa/Khartoum
|
||||
Africa/Kigali
|
||||
Africa/Kinshasa
|
||||
Africa/Lagos
|
||||
Africa/Libreville
|
||||
Africa/Lome
|
||||
Africa/Luanda
|
||||
Africa/Lubumbashi
|
||||
Africa/Lusaka
|
||||
Africa/Malabo
|
||||
Africa/Maputo
|
||||
Africa/Maseru
|
||||
Africa/Mbabane
|
||||
Africa/Mogadishu
|
||||
Africa/Monrovia
|
||||
Africa/Nairobi
|
||||
Africa/Ndjamena
|
||||
Africa/Niamey
|
||||
Africa/Nouakchott
|
||||
Africa/Ouagadougou
|
||||
Africa/Porto-Novo
|
||||
Africa/Sao_Tome
|
||||
Africa/Timbuktu
|
||||
Africa/Tripoli
|
||||
Africa/Tunis
|
||||
Africa/Windhoek
|
||||
|
||||
|
||||
America/Adak
|
||||
America/Anchorage
|
||||
America/Anguilla
|
||||
America/Antigua
|
||||
America/Araguaina
|
||||
America/Argentina/Buenos_Aires
|
||||
America/Argentina/Catamarca
|
||||
America/Argentina/ComodRivadavia
|
||||
America/Argentina/Cordoba
|
||||
America/Argentina/Jujuy
|
||||
America/Argentina/La_Rioja
|
||||
America/Argentina/Mendoza
|
||||
America/Argentina/Rio_Gallegos
|
||||
America/Argentina/San_Juan
|
||||
America/Argentina/Tucuman
|
||||
America/Argentina/Ushuaia
|
||||
America/Aruba
|
||||
America/Asuncion
|
||||
America/Bahia
|
||||
America/Barbados
|
||||
America/Belem
|
||||
America/Belize
|
||||
America/Boa_Vista
|
||||
America/Bogota
|
||||
America/Boise
|
||||
America/Cambridge_Bay
|
||||
America/Campo_Grande
|
||||
America/Cancun
|
||||
America/Caracas
|
||||
America/Cayenne
|
||||
America/Cayman
|
||||
America/Chicago
|
||||
America/Chihuahua
|
||||
America/Costa_Rica
|
||||
America/Cuiaba
|
||||
America/Curacao
|
||||
America/Danmarkshavn
|
||||
America/Dawson
|
||||
America/Dawson_Creek
|
||||
America/Denver
|
||||
America/Detroit
|
||||
America/Dominica
|
||||
America/Edmonton
|
||||
America/Eirunepe
|
||||
America/El_Salvador
|
||||
America/Fortaleza
|
||||
America/Glace_Bay
|
||||
America/Godthab
|
||||
America/Goose_Bay
|
||||
America/Grand_Turk
|
||||
America/Grenada
|
||||
America/Guadeloupe
|
||||
America/Guatemala
|
||||
America/Guayaquil
|
||||
America/Guyana
|
||||
America/Halifax
|
||||
America/Havana
|
||||
America/Hermosillo
|
||||
America/Indiana/Indianapolis
|
||||
America/Indiana/Knox
|
||||
America/Indiana/Marengo
|
||||
America/Indiana/Vevay
|
||||
America/Indianapolis
|
||||
America/Inuvik
|
||||
America/Iqaluit
|
||||
America/Jamaica
|
||||
America/Juneau
|
||||
America/Kentucky/Louisville
|
||||
America/Kentucky/Monticello
|
||||
America/La_Paz
|
||||
America/Lima
|
||||
America/Los_Angeles
|
||||
America/Louisville
|
||||
America/Maceio
|
||||
America/Managua
|
||||
America/Manaus
|
||||
America/Martinique
|
||||
America/Mazatlan
|
||||
America/Menominee
|
||||
America/Merida
|
||||
America/Mexico_City
|
||||
America/Miquelon
|
||||
America/Monterrey
|
||||
America/Montevideo
|
||||
America/Montreal
|
||||
America/Montserrat
|
||||
America/Nassau
|
||||
America/New_York
|
||||
America/Nipigon
|
||||
America/Nome
|
||||
America/Noronha
|
||||
America/North_Dakota/Center
|
||||
America/Panama
|
||||
America/Pangnirtung
|
||||
America/Paramaribo
|
||||
America/Phoenix
|
||||
America/Port-au-Prince
|
||||
America/Port_of_Spain
|
||||
America/Porto_Velho
|
||||
America/Puerto_Rico
|
||||
America/Rainy_River
|
||||
America/Rankin_Inlet
|
||||
America/Recife
|
||||
America/Regina
|
||||
America/Rio_Branco
|
||||
America/Santiago
|
||||
America/Santo_Domingo
|
||||
America/Sao_Paulo
|
||||
America/Scoresbysund
|
||||
America/Shiprock
|
||||
America/St_Johns
|
||||
America/St_Kitts
|
||||
America/St_Lucia
|
||||
America/St_Thomas
|
||||
America/St_Vincent
|
||||
America/Swift_Current
|
||||
America/Tegucigalpa
|
||||
America/Thule
|
||||
America/Thunder_Bay
|
||||
America/Tijuana
|
||||
America/Toronto
|
||||
America/Tortola
|
||||
America/Vancouver
|
||||
America/Whitehorse
|
||||
America/Winnipeg
|
||||
America/Yakutat
|
||||
America/Yellowknife
|
||||
|
||||
|
||||
Antarctica/Casey
|
||||
Antarctica/Davis
|
||||
Antarctica/DumontDUrville
|
||||
Antarctica/Mawson
|
||||
Antarctica/McMurdo
|
||||
Antarctica/Palmer
|
||||
Antarctica/Rothera
|
||||
Antarctica/South_Pole
|
||||
Antarctica/Syowa
|
||||
Antarctica/Vostok
|
||||
|
||||
|
||||
Arctic/Longyearbyen
|
||||
|
||||
|
||||
Asia/Aden
|
||||
Asia/Almaty
|
||||
Asia/Amman
|
||||
Asia/Anadyr
|
||||
Asia/Aqtau
|
||||
Asia/Aqtobe
|
||||
Asia/Ashgabat
|
||||
Asia/Baghdad
|
||||
Asia/Bahrain
|
||||
Asia/Baku
|
||||
Asia/Bangkok
|
||||
Asia/Beirut
|
||||
Asia/Bishkek
|
||||
Asia/Brunei
|
||||
Asia/Calcutta
|
||||
Asia/Choibalsan
|
||||
Asia/Chongqing
|
||||
Asia/Colombo
|
||||
Asia/Damascus
|
||||
Asia/Dhaka
|
||||
Asia/Dili
|
||||
Asia/Dubai
|
||||
Asia/Dushanbe
|
||||
Asia/Gaza
|
||||
Asia/Harbin
|
||||
Asia/Hong_Kong
|
||||
Asia/Hovd
|
||||
Asia/Irkutsk
|
||||
Asia/Istanbul
|
||||
Asia/Jakarta
|
||||
Asia/Jayapura
|
||||
Asia/Jerusalem
|
||||
Asia/Kabul
|
||||
Asia/Kamchatka
|
||||
Asia/Karachi
|
||||
Asia/Kashgar
|
||||
Asia/Katmandu
|
||||
Asia/Krasnoyarsk
|
||||
Asia/Kuala_Lumpur
|
||||
Asia/Kuching
|
||||
Asia/Kuwait
|
||||
Asia/Macau
|
||||
Asia/Magadan
|
||||
Asia/Makassar
|
||||
Asia/Manila
|
||||
Asia/Muscat
|
||||
Asia/Nicosia
|
||||
Asia/Novosibirsk
|
||||
Asia/Omsk
|
||||
Asia/Oral
|
||||
Asia/Phnom_Penh
|
||||
Asia/Pontianak
|
||||
Asia/Pyongyang
|
||||
Asia/Qatar
|
||||
Asia/Qyzylorda
|
||||
Asia/Rangoon
|
||||
Asia/Riyadh
|
||||
Asia/Saigon
|
||||
Asia/Sakhalin
|
||||
Asia/Samarkand
|
||||
Asia/Seoul
|
||||
Asia/Shanghai
|
||||
Asia/Singapore
|
||||
Asia/Taipei
|
||||
Asia/Tashkent
|
||||
Asia/Tbilisi
|
||||
Asia/Tehran
|
||||
Asia/Thimphu
|
||||
Asia/Tokyo
|
||||
Asia/Ulaanbaatar
|
||||
Asia/Urumqi
|
||||
Asia/Vientiane
|
||||
Asia/Vladivostok
|
||||
Asia/Yakutsk
|
||||
Asia/Yekaterinburg
|
||||
Asia/Yerevan
|
||||
|
||||
|
||||
Atlantic/Azores
|
||||
Atlantic/Bermuda
|
||||
Atlantic/Canary
|
||||
Atlantic/Cape_Verde
|
||||
Atlantic/Faeroe
|
||||
Atlantic/Jan_Mayen
|
||||
Atlantic/Madeira
|
||||
Atlantic/Reykjavik
|
||||
Atlantic/South_Georgia
|
||||
Atlantic/St_Helena
|
||||
Atlantic/Stanley
|
||||
|
||||
|
||||
Australia/Adelaide
|
||||
Australia/Brisbane
|
||||
Australia/Broken_Hill
|
||||
Australia/Darwin
|
||||
Australia/Hobart
|
||||
Australia/Lindeman
|
||||
Australia/Lord_Howe
|
||||
Australia/Melbourne
|
||||
Australia/Perth
|
||||
Australia/Sydney
|
||||
|
||||
|
||||
Europe/Amsterdam
|
||||
Europe/Andorra
|
||||
Europe/Athens
|
||||
Europe/Belfast
|
||||
Europe/Belgrade
|
||||
Europe/Berlin
|
||||
Europe/Bratislava
|
||||
Europe/Brussels
|
||||
Europe/Bucharest
|
||||
Europe/Budapest
|
||||
Europe/Chisinau
|
||||
Europe/Copenhagen
|
||||
Europe/Dublin
|
||||
Europe/Gibraltar
|
||||
Europe/Helsinki
|
||||
Europe/Istanbul
|
||||
Europe/Kaliningrad
|
||||
Europe/Kiev
|
||||
Europe/Lisbon
|
||||
Europe/Ljubljana
|
||||
Europe/London
|
||||
Europe/Luxembourg
|
||||
Europe/Madrid
|
||||
Europe/Malta
|
||||
Europe/Mariehamn
|
||||
Europe/Minsk
|
||||
Europe/Monaco
|
||||
Europe/Moscow
|
||||
Europe/Nicosia
|
||||
Europe/Oslo
|
||||
Europe/Paris
|
||||
Europe/Prague
|
||||
Europe/Riga
|
||||
Europe/Rome
|
||||
Europe/Samara
|
||||
Europe/San_Marino
|
||||
Europe/Sarajevo
|
||||
Europe/Simferopol
|
||||
Europe/Skopje
|
||||
Europe/Sofia
|
||||
Europe/Stockholm
|
||||
Europe/Tallinn
|
||||
Europe/Tirane
|
||||
Europe/Uzhgorod
|
||||
Europe/Vaduz
|
||||
Europe/Vatican
|
||||
Europe/Vienna
|
||||
Europe/Vilnius
|
||||
Europe/Warsaw
|
||||
Europe/Zagreb
|
||||
Europe/Zaporozhye
|
||||
Europe/Zurich
|
||||
|
||||
|
||||
Indian/Antananarivo
|
||||
Indian/Chagos
|
||||
Indian/Christmas
|
||||
Indian/Cocos
|
||||
Indian/Comoro
|
||||
Indian/Kerguelen
|
||||
Indian/Mahe
|
||||
Indian/Maldives
|
||||
Indian/Mauritius
|
||||
Indian/Mayotte
|
||||
Indian/Reunion
|
||||
|
||||
|
||||
Pacific/Apia
|
||||
Pacific/Auckland
|
||||
Pacific/Chatham
|
||||
Pacific/Easter
|
||||
Pacific/Efate
|
||||
Pacific/Enderbury
|
||||
Pacific/Fakaofo
|
||||
Pacific/Fiji
|
||||
Pacific/Funafuti
|
||||
Pacific/Galapagos
|
||||
Pacific/Gambier
|
||||
Pacific/Guadalcanal
|
||||
Pacific/Guam
|
||||
Pacific/Honolulu
|
||||
Pacific/Johnston
|
||||
Pacific/Kiritimati
|
||||
Pacific/Kosrae
|
||||
Pacific/Kwajalein
|
||||
Pacific/Majuro
|
||||
Pacific/Marquesas
|
||||
Pacific/Midway
|
||||
Pacific/Nauru
|
||||
Pacific/Niue
|
||||
Pacific/Norfolk
|
||||
Pacific/Noumea
|
||||
Pacific/Pago_Pago
|
||||
Pacific/Palau
|
||||
Pacific/Pitcairn
|
||||
Pacific/Ponape
|
||||
Pacific/Port_Moresby
|
||||
Pacific/Rarotonga
|
||||
Pacific/Saipan
|
||||
Pacific/Tahiti
|
||||
Pacific/Tarawa
|
||||
Pacific/Tongatapu
|
||||
Pacific/Truk
|
||||
Pacific/Wake
|
||||
Pacific/Wallis
|
||||
Pacific/Yap
|
||||
Reference in New Issue
Block a user