mirror of
https://github.com/Lastorder-DC/rhymix.git
synced 2026-04-27 06:13:32 +09:00
Merge pull request #385 from kijin/pr/more-framework-classes
Rhymix Framework 각종 기능 추가
This commit is contained in:
commit
321015e050
269 changed files with 38164 additions and 616 deletions
132
common/framework/calendar.php
Normal file
132
common/framework/calendar.php
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
<?php
|
||||
|
||||
namespace Rhymix\Framework;
|
||||
|
||||
/**
|
||||
* The calendar class.
|
||||
*/
|
||||
class Calendar
|
||||
{
|
||||
/**
|
||||
* This method returns the English name of a month, e.g. 9 = 'September'.
|
||||
*
|
||||
* @param int $month_number
|
||||
* @param bool $long_format (optional, default is true)
|
||||
* @return string
|
||||
*/
|
||||
public static function getMonthName($month_number, $long_format = true)
|
||||
{
|
||||
$month_number = intval($month_number, 10);
|
||||
if (!is_between($month_number, 1, 12))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return date($long_format ? 'F' : 'M', mktime(0, 0, 0, $month_number, 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the day on which a month begins.
|
||||
*
|
||||
* 0 = Sunday, 1 = Monday, 2 = Tuesday, 3 = Wednesday, 4 = Thursday, 5 = Friday, 6 = Saturday.
|
||||
* If you do not specify a year, the current year is assumed.
|
||||
*
|
||||
* @param int $month_number
|
||||
* @param int $year (optional)
|
||||
* @return int
|
||||
*/
|
||||
public static function getMonthStartDayOfWeek($month_number, $year = null)
|
||||
{
|
||||
$month_number = intval($month_number, 10);
|
||||
if (!is_between($month_number, 1, 12))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return (int)date('w', mktime(0, 0, 0, $month_number, 1, $year ?: date('Y')));
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the number of days in a month, e.g. February 2016 has 29 days.
|
||||
*
|
||||
* If you do not specify a year, the current year is assumed.
|
||||
* You must specify a year to get the number of days in February.
|
||||
*
|
||||
* @param int $month_number
|
||||
* @param int $year (optional)
|
||||
* @return int
|
||||
*/
|
||||
public static function getMonthDays($month_number, $year = null)
|
||||
{
|
||||
$month_number = intval($month_number, 10);
|
||||
if (!is_between($month_number, 1, 12))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return (int)date('t', mktime(0, 0, 0, $month_number, 1, $year ?: date('Y')));
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns a complete calendar for a month.
|
||||
*
|
||||
* The return value is an array with six members, each representing a week.
|
||||
* Each week is an array with seven members, each representing a day.
|
||||
* 6 weeks are returned. Empty cells are represented by nulls.
|
||||
*
|
||||
* If you do not specify a year, the current year is assumed.
|
||||
*
|
||||
* @param int $month_number
|
||||
* @param int $year (optional)
|
||||
* @param int $start_dow (optional)
|
||||
* @return array
|
||||
*/
|
||||
public static function getMonthCalendar($month_number, $year = null, $start_dow = 0)
|
||||
{
|
||||
$month_number = intval($month_number, 10);
|
||||
if (!is_between($month_number, 1, 12))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!is_between($start_dow, 0, 6))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!$year || !is_between($year, 1000, 9999))
|
||||
{
|
||||
$year = date('Y');
|
||||
}
|
||||
|
||||
$start = self::getMonthStartDayOfWeek($month_number, $year);
|
||||
$count = self::getMonthDays($month_number, $year);
|
||||
$initial_blank_cells = (7 + $start - $start_dow) % 7;
|
||||
$final_blank_cells = 42 - $count - $initial_blank_cells;
|
||||
$temp = array();
|
||||
|
||||
for ($i = 0; $i < $initial_blank_cells; $i++)
|
||||
{
|
||||
$temp[] = null;
|
||||
}
|
||||
for ($i = 0; $i < $count; $i++)
|
||||
{
|
||||
$temp[] = $i + 1;
|
||||
}
|
||||
for ($i = 0; $i < $final_blank_cells; $i++)
|
||||
{
|
||||
$temp[] = null;
|
||||
}
|
||||
|
||||
$return = array();
|
||||
for ($i = 0; $i < 6; $i++)
|
||||
{
|
||||
$week = array();
|
||||
for ($j = 0; $j < 7; $j++)
|
||||
{
|
||||
$week[] = array_shift($temp);
|
||||
}
|
||||
$return[] = $week;
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
}
|
||||
|
|
@ -28,9 +28,9 @@ class Config
|
|||
*/
|
||||
public static function init()
|
||||
{
|
||||
if (file_exists(RX_BASEDIR . self::$config_filename))
|
||||
if (file_exists(\RX_BASEDIR . self::$config_filename))
|
||||
{
|
||||
self::$_config = (include RX_BASEDIR . self::$config_filename);
|
||||
self::$_config = (include \RX_BASEDIR . self::$config_filename);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -59,7 +59,7 @@ class Config
|
|||
*/
|
||||
public static function getDefaults()
|
||||
{
|
||||
return (include RX_BASEDIR . self::$default_config_filename);
|
||||
return (include \RX_BASEDIR . self::$default_config_filename);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -135,7 +135,7 @@ class Config
|
|||
|
||||
// Save the main config file.
|
||||
$buff = '<?php' . "\n" . '// Rhymix System Configuration' . "\n" . 'return ' . self::serialize(self::$_config) . ';' . "\n";
|
||||
$result = \FileHandler::writeFile(RX_BASEDIR . self::$config_filename, $buff) ? true : false;
|
||||
$result = Storage::write(\RX_BASEDIR . self::$config_filename, $buff) ? true : false;
|
||||
//if (!$result) return false;
|
||||
|
||||
// Save XE-compatible config files.
|
||||
|
|
@ -144,9 +144,9 @@ class Config
|
|||
$db_info_without_ftp = clone $db_info;
|
||||
unset($db_info_without_ftp->ftp_info);
|
||||
$buff = '<?php' . "\n" . '$db_info = ' . self::serialize($db_info_without_ftp) . ';' . "\n";
|
||||
\FileHandler::writeFile(RX_BASEDIR . self::$old_db_config_filename, $buff);
|
||||
Storage::write(\RX_BASEDIR . self::$old_db_config_filename, $buff);
|
||||
$buff = '<?php' . "\n" . '$ftp_info = ' . self::serialize($ftp_info) . ';' . "\n";
|
||||
\FileHandler::writeFile(RX_BASEDIR . self::$old_ftp_config_filename, $buff);
|
||||
Storage::write(\RX_BASEDIR . self::$old_ftp_config_filename, $buff);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -173,8 +173,8 @@ class Debug
|
|||
|
||||
// Rewrite the error message with relative paths.
|
||||
$message = str_replace(array(
|
||||
' called in ' . RX_BASEDIR,
|
||||
' defined in ' . RX_BASEDIR,
|
||||
' called in ' . \RX_BASEDIR,
|
||||
' defined in ' . \RX_BASEDIR,
|
||||
), array(
|
||||
' called in ',
|
||||
' defined in ',
|
||||
|
|
@ -485,7 +485,7 @@ class Debug
|
|||
{
|
||||
// Collect debug information.
|
||||
$data = (object)array(
|
||||
'timestamp' => DateTime::formatTimestamp('Y-m-d H:i:s', RX_TIME),
|
||||
'timestamp' => DateTime::formatTimestamp('Y-m-d H:i:s', \RX_TIME),
|
||||
'url' => getCurrentPageUrl(),
|
||||
'request' => (object)array(
|
||||
'method' => $_SERVER['REQUEST_METHOD'] . ($_SERVER['REQUEST_METHOD'] !== \Context::getRequestMethod() ? (' (' . \Context::getRequestMethod() . ')') : ''),
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
namespace Rhymix\Framework\Filters;
|
||||
|
||||
use Rhymix\Framework\Security;
|
||||
use Rhymix\Framework\Storage;
|
||||
|
||||
/**
|
||||
* The HTML filter class.
|
||||
|
|
@ -126,8 +127,8 @@ class HTMLFilter
|
|||
$config->set('URI.SafeIframeRegexp', MediaFilter::getIframeWhitelistRegex());
|
||||
|
||||
// Set the serializer path.
|
||||
$config->set('Cache.SerializerPath', RX_BASEDIR . 'files/cache/htmlpurifier');
|
||||
\FileHandler::makeDir(RX_BASEDIR . 'files/cache/htmlpurifier');
|
||||
$config->set('Cache.SerializerPath', \RX_BASEDIR . 'files/cache/htmlpurifier');
|
||||
Storage::createDirectory(\RX_BASEDIR . 'files/cache/htmlpurifier');
|
||||
|
||||
// Modify the HTML definition to support editor components and widgets.
|
||||
$def = $config->getHTMLDefinition(true);
|
||||
|
|
@ -313,8 +314,8 @@ class HTMLFilter
|
|||
|
||||
// flexbox
|
||||
$info['display'] = new \HTMLPurifier_AttrDef_Enum(array(
|
||||
'block', 'flex', '-webkit-flex', 'inline', 'inline-block', 'inline-flex', '-webkit-inline-flex', 'inline-table',
|
||||
'list-item', 'run-in', 'compact', 'marker', 'table', 'table-row-group', 'table-header-group', 'table-footer-group',
|
||||
'block', 'flex', '-webkit-flex', 'inline', 'inline-block', 'inline-flex', '-webkit-inline-flex', 'inline-table',
|
||||
'list-item', 'run-in', 'compact', 'marker', 'table', 'table-row-group', 'table-header-group', 'table-footer-group',
|
||||
'table-row', 'table-column-group', 'table-column', 'table-cell', 'table-caption',
|
||||
'none', 'initial', 'inherit',
|
||||
));
|
||||
|
|
|
|||
|
|
@ -140,7 +140,7 @@ class IpFilter
|
|||
return false;
|
||||
}
|
||||
|
||||
$cloudflare_ranges = (include RX_BASEDIR . 'common/defaults/cloudflare.php');
|
||||
$cloudflare_ranges = (include \RX_BASEDIR . 'common/defaults/cloudflare.php');
|
||||
foreach ($cloudflare_ranges as $cloudflare_range)
|
||||
{
|
||||
if (self::inRange($_SERVER['REMOTE_ADDR'], $cloudflare_range))
|
||||
|
|
|
|||
|
|
@ -198,7 +198,7 @@ class MediaFilter
|
|||
*/
|
||||
protected static function _loadWhitelists($custom_whitelist = array())
|
||||
{
|
||||
$default_whitelist = (include RX_BASEDIR . 'common/defaults/whitelist.php');
|
||||
$default_whitelist = (include \RX_BASEDIR . 'common/defaults/whitelist.php');
|
||||
self::$_object_whitelist = array();
|
||||
self::$_iframe_whitelist = array();
|
||||
|
||||
|
|
|
|||
311
common/framework/formatter.php
Normal file
311
common/framework/formatter.php
Normal file
|
|
@ -0,0 +1,311 @@
|
|||
<?php
|
||||
|
||||
namespace Rhymix\Framework;
|
||||
|
||||
/**
|
||||
* The formatter class.
|
||||
*/
|
||||
class Formatter
|
||||
{
|
||||
/**
|
||||
* Options for text to HTML conversion.
|
||||
*/
|
||||
const TEXT_NEWLINE_AS_P = 1;
|
||||
const TEXT_DOUBLE_NEWLINE_AS_P = 2;
|
||||
|
||||
/**
|
||||
* Options for Markdown to HTML conversion.
|
||||
*/
|
||||
const MD_NEWLINE_AS_BR = 16;
|
||||
const MD_ENABLE_EXTRA = 128;
|
||||
|
||||
/**
|
||||
* Convert plain text to HTML.
|
||||
*
|
||||
* @param string $text
|
||||
* @param int $options (optional)
|
||||
* @return string
|
||||
*/
|
||||
public static function text2html($text, $options = 0)
|
||||
{
|
||||
// This option uses <p> instead of <br> to separate lines.
|
||||
if ($options & self::TEXT_NEWLINE_AS_P)
|
||||
{
|
||||
$lines = array_map('trim', explode("\n", escape(trim($text))));
|
||||
$result = '';
|
||||
foreach ($lines as $line)
|
||||
{
|
||||
$result .= "<p>$line</p>\n";
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
// This option uses <br> to separate lines and <p> to separate paragraphs.
|
||||
if ($options & self::TEXT_DOUBLE_NEWLINE_AS_P)
|
||||
{
|
||||
$lines = preg_replace('!(<br />)+\s*$!', '', nl2br(escape(trim($text))));
|
||||
$lines = preg_split('!(<br />\s*)+<br />!', $lines);
|
||||
foreach ($lines as $line)
|
||||
{
|
||||
$result .= "<p>\n" . trim($line) . "\n</p>\n";
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
// The default is to use <br> always.
|
||||
return nl2br(escape(trim($text))) . "<br />\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert HTML to plain text.
|
||||
*
|
||||
* @param string $html
|
||||
* @return string
|
||||
*/
|
||||
public static function html2text($html)
|
||||
{
|
||||
// Add line breaks after <br> and <p> tags.
|
||||
$html = preg_replace('!<br[^>]*>\s*!i', "\n", $html);
|
||||
$html = preg_replace('!<p\b[^>]*>\s*!i', '', $html);
|
||||
$html = preg_replace('!</p[^>]*>\s*!i', "\n\n", $html);
|
||||
|
||||
// Encode links and images to preserve essential information.
|
||||
$html = preg_replace_callback('!<a\b[^>]*href="([^>"]+)"[^>]*>([^<]*)</a>!i', function($matches) {
|
||||
return trim($matches[2] . ' <' . $matches[1] . '>');
|
||||
}, $html);
|
||||
$html = preg_replace_callback('!<img\b[^>]*src="([^>"]+)"[^>]*>!i', function($matches) {
|
||||
$title = preg_match('!title="([^>"]+)"!i', $matches[0], $m) ? $m[1] : null;
|
||||
$title = $title ?: (preg_match('!alt="([^>"]+)"!i', $matches[0], $m) ? $m[1] : 'IMAGE');
|
||||
return trim('[' . $title . '] <' . $matches[1] . '>');
|
||||
}, $html);
|
||||
|
||||
// Strip all other HTML.
|
||||
$text = html_entity_decode(strip_tags($html));
|
||||
unset($html);
|
||||
|
||||
// Normalize whitespace and return.
|
||||
$text = str_replace("\r\n", "\n", $text);
|
||||
$text = preg_replace('/\n(?:\s*\n)+/', "\n\n", $text);
|
||||
return trim($text) . "\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert Markdown to HTML.
|
||||
*
|
||||
* @param string $markdown
|
||||
* @param int $options (optional)
|
||||
* @return string
|
||||
*/
|
||||
public static function markdown2html($markdown, $options = 0)
|
||||
{
|
||||
if ($options & self::MD_NEWLINE_AS_BR)
|
||||
{
|
||||
$markdown = preg_replace('/(?<!\n)\n(?![\n\*\#\-])/', " \n", $markdown);
|
||||
}
|
||||
|
||||
if ($options & self::MD_ENABLE_EXTRA)
|
||||
{
|
||||
$class_name = '\\Michelf\\MarkdownExtra';
|
||||
}
|
||||
else
|
||||
{
|
||||
$class_name = '\\Michelf\\Markdown';
|
||||
}
|
||||
|
||||
$html = $class_name::defaultTransform($markdown);
|
||||
return Filters\HTMLFilter::clean($html);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert HTML to Markdown.
|
||||
*
|
||||
* @param string $html
|
||||
* @return string
|
||||
*/
|
||||
public static function html2markdown($html)
|
||||
{
|
||||
$converter = new \League\HTMLToMarkdown\HtmlConverter();
|
||||
$converter->getConfig()->setOption('bold_style', '**');
|
||||
$converter->getConfig()->setOption('italic_style', '_');
|
||||
$converter->getConfig()->setOption('strip_tags', true);
|
||||
return trim($converter->convert($html)) . "\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert BBCode to HTML.
|
||||
*
|
||||
* @param string $bbcode
|
||||
* @return string
|
||||
*/
|
||||
public static function bbcode($bbcode)
|
||||
{
|
||||
$parser = new \JBBCode\Parser;
|
||||
$parser->addCodeDefinitionSet(new \JBBCode\DefaultCodeDefinitionSet());
|
||||
|
||||
$builder = new \JBBCode\CodeDefinitionBuilder('quote', '<blockquote>{param}</blockquote>');
|
||||
$parser->addCodeDefinition($builder->build());
|
||||
$builder = new \JBBCode\CodeDefinitionBuilder('code', '<pre><code>{param}</code></pre>');
|
||||
$builder->setParseContent(false);
|
||||
$parser->addCodeDefinition($builder->build());
|
||||
|
||||
$parser->parse($bbcode);
|
||||
$html = $parser->getAsHtml();
|
||||
return Filters\HTMLFilter::clean($html);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply smart quotes and other stylistic enhancements to HTML.
|
||||
*
|
||||
* @param string $html
|
||||
* @return string
|
||||
*/
|
||||
public static function applySmartQuotes($html)
|
||||
{
|
||||
return \Michelf\SmartyPants::defaultTransform($html, 'qbBdDiew');
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile LESS into CSS.
|
||||
*
|
||||
* @param string|array $source_filename
|
||||
* @param string $target_filename
|
||||
* @param array $variables (optional)
|
||||
* @parsm bool $minify (optional)
|
||||
* @return bool
|
||||
*/
|
||||
public static function compileLESS($source_filename, $target_filename, $variables = array(), $minify = false)
|
||||
{
|
||||
// Get the cleaned and concatenated content.
|
||||
$content = self::_concatenate($source_filename, $target_filename);
|
||||
|
||||
// Compile!
|
||||
try
|
||||
{
|
||||
$less_compiler = new \lessc;
|
||||
$less_compiler->setFormatter($minify ? 'compressed' : 'lessjs');
|
||||
$less_compiler->setImportDir(array(dirname(is_array($source_filename) ? array_first($source_filename) : $source_filename)));
|
||||
if ($variables)
|
||||
{
|
||||
$less_compiler->setVariables($variables);
|
||||
}
|
||||
|
||||
$content = '@charset "UTF-8";' . "\n" . $less_compiler->compile($content) . "\n";
|
||||
$result = true;
|
||||
}
|
||||
catch (\Exception $e)
|
||||
{
|
||||
$content = '/*' . "\n" . 'Error while compiling LESS:' . "\n" . $e->getMessage() . "\n" . '*/' . "\n";
|
||||
$result = false;
|
||||
}
|
||||
|
||||
// Save the result to the target file.
|
||||
Storage::write($target_filename, $content);
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile SCSS into CSS.
|
||||
*
|
||||
* @param string|array $source_filename
|
||||
* @param string $target_filename
|
||||
* @param array $variables (optional)
|
||||
* @parsm bool $minify (optional)
|
||||
* @return bool
|
||||
*/
|
||||
public static function compileSCSS($source_filename, $target_filename, $variables = array(), $minify = false)
|
||||
{
|
||||
// Get the cleaned and concatenated content.
|
||||
$content = self::_concatenate($source_filename, $target_filename);
|
||||
|
||||
// Compile!
|
||||
try
|
||||
{
|
||||
$scss_compiler = new \scssc;
|
||||
$scss_compiler->setFormatter($minify ? 'scss_formatter_compressed' : 'scss_formatter');
|
||||
$scss_compiler->setImportPaths(array(dirname(is_array($source_filename) ? array_first($source_filename) : $source_filename)));
|
||||
if ($variables)
|
||||
{
|
||||
$scss_compiler->setVariables($variables);
|
||||
}
|
||||
|
||||
$content = '@charset "UTF-8";' . "\n" . $scss_compiler->compile($content) . "\n";
|
||||
$result = true;
|
||||
}
|
||||
catch (\Exception $e)
|
||||
{
|
||||
$content = '/*' . "\n" . 'Error while compiling SCSS:' . "\n" . $e->getMessage() . "\n" . '*/' . "\n";
|
||||
$result = false;
|
||||
}
|
||||
|
||||
// Save the result to the target file.
|
||||
Storage::write($target_filename, $content);
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Minify CSS.
|
||||
*
|
||||
* @param string|array $source_filename
|
||||
* @param string $target_filename
|
||||
* @return bool
|
||||
*/
|
||||
public static function minifyCSS($source_filename, $target_filename)
|
||||
{
|
||||
$minifier = new \MatthiasMullie\Minify\CSS($source_filename);
|
||||
$content = $minifier->execute($target_filename);
|
||||
Storage::write($target_filename, $content);
|
||||
return strlen($content) ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Minify JS.
|
||||
*
|
||||
* @param string|array $source_filename
|
||||
* @param string $target_filename
|
||||
* @return bool
|
||||
*/
|
||||
public static function minifyJS($source_filename, $target_filename)
|
||||
{
|
||||
$minifier = new \MatthiasMullie\Minify\JS($source_filename);
|
||||
$content = $minifier->execute($target_filename);
|
||||
Storage::write($target_filename, $content);
|
||||
return strlen($content) ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* CSS concatenation subroutine for compileLESS() and compileSCSS().
|
||||
*
|
||||
* @param string|array $source_filename
|
||||
* @param string $target_filename
|
||||
* @return string
|
||||
*/
|
||||
protected static function _concatenate($source_filename, $target_filename)
|
||||
{
|
||||
$result = '';
|
||||
|
||||
if (!is_array($source_filename))
|
||||
{
|
||||
$source_filename = array($source_filename);
|
||||
}
|
||||
foreach ($source_filename as $filename)
|
||||
{
|
||||
$content = utf8_clean(file_get_contents($filename));
|
||||
$path_converter = new \MatthiasMullie\PathConverter\Converter($filename, $target_filename);
|
||||
$content = preg_replace_callback('/\burl\\(([^)]+)\\)/iU', function($matches) use ($path_converter) {
|
||||
$url = trim($matches[1], '\'"');
|
||||
if (!strlen($url) || $url[0] === '/')
|
||||
{
|
||||
return $matches[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
return 'url("' . escape_dqstr($path_converter->convert($url)) . '")';
|
||||
}
|
||||
}, $content);
|
||||
unset($path_converter);
|
||||
$result .= trim($content) . "\n\n";
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
78
common/framework/i18n.php
Normal file
78
common/framework/i18n.php
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
<?php
|
||||
|
||||
namespace Rhymix\Framework;
|
||||
|
||||
/**
|
||||
* The i18n (internationalization) class.
|
||||
*/
|
||||
class i18n
|
||||
{
|
||||
/**
|
||||
* Constants for sorting.
|
||||
*/
|
||||
const SORT_CODE_2 = 2;
|
||||
const SORT_CODE_3 = 3;
|
||||
const SORT_CODE_NUMERIC = 4;
|
||||
const SORT_CCTLD = 5;
|
||||
const SORT_NAME_ENGLISH = 6;
|
||||
const SORT_NAME_KOREAN = 7;
|
||||
const SORT_NAME_NATIVE = 8;
|
||||
|
||||
/**
|
||||
* Get the list of all countries.
|
||||
*
|
||||
* @param int $sort_by
|
||||
* @return array
|
||||
*/
|
||||
public static function listCountries($sort_by = self::SORT_NAME_ENGLISH)
|
||||
{
|
||||
$countries = (include \RX_BASEDIR . 'common/defaults/countries.php');
|
||||
$result = array();
|
||||
|
||||
foreach ($countries as $country)
|
||||
{
|
||||
$result[$country['iso_3166_1_alpha3']] = (object)$country;
|
||||
}
|
||||
|
||||
switch ($sort_by)
|
||||
{
|
||||
case self::SORT_CODE_2:
|
||||
uasort($result, function($a, $b) {
|
||||
return strcmp($a->iso_3166_1_alpha2, $b->iso_3166_1_alpha2);
|
||||
});
|
||||
break;
|
||||
case self::SORT_CODE_3:
|
||||
uasort($result, function($a, $b) {
|
||||
return strcmp($a->iso_3166_1_alpha3, $b->iso_3166_1_alpha3);
|
||||
});
|
||||
break;
|
||||
case self::SORT_CODE_NUMERIC:
|
||||
uasort($result, function($a, $b) {
|
||||
return strcmp($a->iso_3166_1_numeric, $b->iso_3166_1_numeric);
|
||||
});
|
||||
break;
|
||||
case self::SORT_CCTLD:
|
||||
uasort($result, function($a, $b) {
|
||||
return strcmp($a->cctld, $b->cctld);
|
||||
});
|
||||
break;
|
||||
case self::SORT_NAME_ENGLISH:
|
||||
uasort($result, function($a, $b) {
|
||||
return strcmp($a->name_english, $b->name_english);
|
||||
});
|
||||
break;
|
||||
case self::SORT_NAME_KOREAN:
|
||||
uasort($result, function($a, $b) {
|
||||
return strcmp($a->name_korean, $b->name_korean);
|
||||
});
|
||||
break;
|
||||
case self::SORT_NAME_NATIVE:
|
||||
uasort($result, function($a, $b) {
|
||||
return strcmp($a->name_native, $b->name_native);
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
453
common/framework/korea.php
Normal file
453
common/framework/korea.php
Normal file
|
|
@ -0,0 +1,453 @@
|
|||
<?php
|
||||
|
||||
namespace Rhymix\Framework;
|
||||
|
||||
/**
|
||||
* Class for validating Korea-specific information.
|
||||
*/
|
||||
class Korea
|
||||
{
|
||||
/**
|
||||
* Format a phone number.
|
||||
*
|
||||
* @param string $num
|
||||
* @return string
|
||||
*/
|
||||
public static function formatPhoneNumber($num)
|
||||
{
|
||||
// Remove all non-numbers.
|
||||
$num = preg_replace('/[^0-9]/', '', $num);
|
||||
|
||||
// Remove the country code.
|
||||
if (strncmp($num, '82', 2) === 0)
|
||||
{
|
||||
$num = substr($num, 2);
|
||||
if (strncmp($num, '0', 1) !== 0)
|
||||
{
|
||||
$num = '0' . $num;
|
||||
}
|
||||
}
|
||||
|
||||
// Apply different format based on the number of digits.
|
||||
switch (strlen($num))
|
||||
{
|
||||
case 8:
|
||||
return substr($num, 0, 4) . '-' . substr($num, 4);
|
||||
case 9:
|
||||
return substr($num, 0, 2) . '-' . substr($num, 2, 3) . '-' . substr($num, 5);
|
||||
case 10:
|
||||
if (substr($num, 0, 2) === '02')
|
||||
{
|
||||
return substr($num, 0, 2) . '-' . substr($num, 2, 4) . '-' . substr($num, 6);
|
||||
}
|
||||
else
|
||||
{
|
||||
return substr($num, 0, 3) . '-' . substr($num, 3, 3) . '-' . substr($num, 6);
|
||||
}
|
||||
default:
|
||||
if (substr($num, 0, 4) === '0303' || substr($num, 0, 3) === '050')
|
||||
{
|
||||
return substr($num, 0, 4) . '-' . substr($num, 4, 3) . '-' . substr($num, 7);
|
||||
}
|
||||
else
|
||||
{
|
||||
return substr($num, 0, 3) . '-' . substr($num, 3, 4) . '-' . substr($num, 7);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a Korean phone number contains a valid area code and the correct number of digits.
|
||||
*
|
||||
* @param string $num
|
||||
* @return bool
|
||||
*/
|
||||
public static function isValidPhoneNumber($num)
|
||||
{
|
||||
$num = str_replace('-', '', self::formatPhoneNumber($num));
|
||||
if (preg_match('/^1[0-9]{7}$/', $num))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (preg_match('/^02[2-9][0-9]{6,7}$/', $num))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (preg_match('/^0[13-8][0-9][2-9][0-9]{6,7}$/', $num))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a Korean phone number is a mobile phone number.
|
||||
*
|
||||
* @param string $num
|
||||
* @return bool
|
||||
*/
|
||||
public static function isValidMobilePhoneNumber($num)
|
||||
{
|
||||
$num = str_replace('-', '', self::formatPhoneNumber($num));
|
||||
$len = strlen($num);
|
||||
return preg_match('/^01[016789][2-9][0-9]{6,7}$/', $num) ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given string is a valid resident registration number (주민등록번호)
|
||||
* or foreigner registration number (외국인등록번호).
|
||||
*
|
||||
* This method only checks the format.
|
||||
* It does not check that the number is actually in use.
|
||||
*
|
||||
* @param string $code
|
||||
* @return bool
|
||||
*/
|
||||
public static function isValidJuminNumber($code)
|
||||
{
|
||||
// Return false if the format is obviously wrong.
|
||||
if (!preg_match('/^[0-9]{6}-?[0-9]{7}$/', $code))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove hyphen.
|
||||
$code = str_replace('-', '', $code);
|
||||
|
||||
// Return false if the date of birth is in the future.
|
||||
if (in_array((int)($code[6]), array(3, 4, 7, 8)) && intval(substr($code, 0, 6), 10) > date('ymd'))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Calculate the checksum.
|
||||
$sum = 0;
|
||||
for ($i = 0; $i < 12; $i++)
|
||||
{
|
||||
$sum += $code[$i] * (($i % 8) + 2);
|
||||
}
|
||||
$checksum = (11 - ($sum % 11)) % 10;
|
||||
if (in_array((int)($code[6]), array(1, 2, 3, 4, 9, 0)))
|
||||
{
|
||||
return $checksum === (int)($code[12]);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (substr($code, 7, 2) % 2 !== 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (($checksum + 2) % 10) === (int)($code[12]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given string is a valid corporation registration number (법인등록번호).
|
||||
*
|
||||
* This method only checks the format.
|
||||
* It does not check that the number is actually in use.
|
||||
*
|
||||
* @param string $code
|
||||
* @return bool
|
||||
*/
|
||||
public static function isValidCorporationNumber($code)
|
||||
{
|
||||
// Return false if the format is obviously wrong.
|
||||
if (!preg_match('/^[0-9]{6}-?[0-9]{7}$/', $code))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove hyphen.
|
||||
$code = str_replace('-', '', $code);
|
||||
|
||||
// Calculate the checksum.
|
||||
$sum = 0;
|
||||
for ($i = 0; $i < 12; $i++)
|
||||
{
|
||||
$sum += $code[$i] * (($i % 2) + 1);
|
||||
}
|
||||
$checksum = (10 - ($sum % 10)) % 10;
|
||||
|
||||
// Check the 7th and 13th digits.
|
||||
if ($code[6] !== '0')
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return $checksum === (int)($code[12]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given string is a valid business registration number (사업자등록번호).
|
||||
*
|
||||
* This method only checks the format.
|
||||
* It does not check that the number is actually in use.
|
||||
*
|
||||
* @param string $code
|
||||
* @return bool
|
||||
*/
|
||||
public static function isValidBusinessNumber($code)
|
||||
{
|
||||
// Return false if the format is obviously wrong.
|
||||
if (!preg_match('/^[0-9]{3}-?[0-9]{2}-?[0-9]{5}$/', $code))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove hyphen.
|
||||
$code = str_replace('-', '', $code);
|
||||
|
||||
// Calculate the checksum.
|
||||
$sum = 0;
|
||||
$sum += $code[0] + ($code[1] * 3) + ($code[2] * 7);
|
||||
$sum += $code[3] + ($code[4] * 3) + ($code[5] * 7);
|
||||
$sum += $code[6] + ($code[7] * 3) + ($code[8] * 5);
|
||||
$sum += floor(($code[8] * 5) / 10);
|
||||
$checksum = (10 - ($sum % 10)) % 10;
|
||||
|
||||
// Check the last digit.
|
||||
return $checksum === (int)($code[9]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given IP address is Korean.
|
||||
*
|
||||
* This method may return incorrect results if the IP allocation databases
|
||||
* (korea.ipv4.php, korea.ipv6.php) are out of date.
|
||||
*
|
||||
* @param string $ip
|
||||
* @return bool
|
||||
*/
|
||||
public static function isKoreanIP($ip)
|
||||
{
|
||||
// Extract the IPv4 address from an "IPv4-mapped IPv6" address.
|
||||
if (preg_match('/::ffff:(?:0+:)?([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)$/', $ip, $matches)) $ip = $matches[1];
|
||||
|
||||
// Return false if the IP address is not in the right format.
|
||||
if (!filter_var($ip, \FILTER_VALIDATE_IP)) return false;
|
||||
|
||||
// Check IPv4.
|
||||
if (filter_var($ip, \FILTER_VALIDATE_IP, array('flags' => \FILTER_FLAG_IPV4)))
|
||||
{
|
||||
// Convert to integer.
|
||||
$ipnum = sprintf('%u', ip2long($ip));
|
||||
|
||||
// Treat local addresses as Korean.
|
||||
if ($ipnum >= 167772160 && $ipnum <= 184549375) return true; // 10.0.0.0/8
|
||||
if ($ipnum >= 2130706432 && $ipnum <= 2147483647) return true; // 127.0.0.0/8
|
||||
if ($ipnum >= 3232235520 && $ipnum <= 3232301055) return true; // 192.168.0.0/16
|
||||
if ($ipnum >= 2886729728 && $ipnum <= 2887778303) return true; // 172.16.0.0/20
|
||||
|
||||
// Check the IPv4 allocation database.
|
||||
$ranges = (include \RX_BASEDIR . 'common/defaults/korea.ipv4.php');
|
||||
foreach ($ranges as $range)
|
||||
{
|
||||
if ($ipnum >= $range[0] && $ipnum <= $range[1]) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check IPv6.
|
||||
elseif (function_exists('inet_pton'))
|
||||
{
|
||||
// Convert to hexadecimal format.
|
||||
$ipbin = strtolower(bin2hex(inet_pton($ip)));
|
||||
|
||||
// Treat local addresses as Korean.
|
||||
if ($ipbin == '00000000000000000000000000000001') return true; // ::1
|
||||
if (preg_match('/^f(?:[cd]|e80{13})/', $ipbin)) return true; // fc00::/8, fd00::/8, fe80::/64
|
||||
|
||||
// Check the IPv6 allocation database.
|
||||
$ranges = (include \RX_BASEDIR . 'common/defaults/korea.ipv6.php');
|
||||
foreach ($ranges as $range)
|
||||
{
|
||||
if (strncmp($ipbin, $range[0], 16) >= 0 && strncmp($ipbin, $range[1], 16) <= 0) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given email address is hosted by a Korean portal site.
|
||||
*
|
||||
* This can be used to tell which recipients may subscribe to the KISA RBL (kisarbl.or.kr).
|
||||
* If the domain is not found, this method returns false.
|
||||
*
|
||||
* @param string $domain
|
||||
* @param bool $clear_cache (optional)
|
||||
* @return bool
|
||||
*/
|
||||
public static function isKoreanEmailAddress($email_address, $clear_cache = false)
|
||||
{
|
||||
// Clear the cache if requested.
|
||||
if ($clear_cache)
|
||||
{
|
||||
self::$_domain_cache = array();
|
||||
}
|
||||
|
||||
// Get the domain from the email address.
|
||||
if ($pos = strpos($email_address, '@'))
|
||||
{
|
||||
$domain = substr($email_address, $pos + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
$domain = $email_address;
|
||||
}
|
||||
$domain = rtrim(strtolower($domain), '.');
|
||||
|
||||
// Return cached result if available.
|
||||
if (array_key_exists($domain, self::$_domain_cache))
|
||||
{
|
||||
return self::$_domain_cache[$domain];
|
||||
}
|
||||
|
||||
// Shortcut for known domains.
|
||||
if (in_array($domain, self::$known_korean))
|
||||
{
|
||||
return self::$_domain_cache[$domain] = true;
|
||||
}
|
||||
if (in_array($domain, self::$known_foreign))
|
||||
{
|
||||
return self::$_domain_cache[$domain] = false;
|
||||
}
|
||||
|
||||
// For unknown domains, check the MX record.
|
||||
$mx = self::_getDNSRecords($domain, \DNS_MX);
|
||||
|
||||
$i = 0;
|
||||
foreach ($mx as $mx)
|
||||
{
|
||||
$mx = rtrim($mx, '.');
|
||||
foreach (self::$known_korean as $portal)
|
||||
{
|
||||
if ($mx === $portal || ends_with('.' . $portal, $mx))
|
||||
{
|
||||
return self::$_domain_cache[$domain] = true;
|
||||
}
|
||||
}
|
||||
foreach (self::$known_foreign as $portal)
|
||||
{
|
||||
if ($mx === $portal || ends_with('.' . $portal, $mx))
|
||||
{
|
||||
return self::$_domain_cache[$domain] = false;
|
||||
}
|
||||
}
|
||||
foreach (self::_getDNSRecords($domain, \DNS_A) as $mx_ip)
|
||||
{
|
||||
return self::$_domain_cache[$domain] = self::isKoreanIP($mx_ip);
|
||||
}
|
||||
if (++$i > 2)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return self::$_domain_cache[$domain] = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the DNS records of a domain.
|
||||
*
|
||||
* @param string $domain
|
||||
* @param int $type
|
||||
* @return array
|
||||
*/
|
||||
protected static function _getDNSRecords($domain, $type)
|
||||
{
|
||||
$records = dns_get_record($domain, $type);
|
||||
if (!$records)
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
$result = array();
|
||||
foreach ($records as $record)
|
||||
{
|
||||
if (isset($record['pri']) && isset($record['target']))
|
||||
{
|
||||
$result[intval($record['pri'])] = $record['target'];
|
||||
}
|
||||
elseif (isset($record['target']))
|
||||
{
|
||||
$result[] = $record['target'];
|
||||
}
|
||||
elseif (isset($record['ip']) || isset($record['ipv6']))
|
||||
{
|
||||
$result[] = isset($record['ip']) ? $record['ip'] : $record['ipv6'];
|
||||
}
|
||||
elseif (isset($record['txt']))
|
||||
{
|
||||
$result[] = $record['txt'];
|
||||
}
|
||||
}
|
||||
|
||||
ksort($result);
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent multiple lookups for the same domain.
|
||||
*/
|
||||
protected static $_domain_cache = array();
|
||||
|
||||
/**
|
||||
* Domains known to be Korean and subscribed to the KISA RBL.
|
||||
*/
|
||||
public static $known_korean = array(
|
||||
'hanmail.net',
|
||||
'hanmail2.net',
|
||||
'daum.net',
|
||||
'paran.com',
|
||||
'tistory.com',
|
||||
'naver.com',
|
||||
'navercorp.com',
|
||||
'nate.com',
|
||||
'cyworld.com',
|
||||
'dreamwiz.com',
|
||||
'korea.com',
|
||||
'dreamx.com',
|
||||
'chol.com',
|
||||
'chollian.net',
|
||||
'hanmir.com',
|
||||
'hitel.com',
|
||||
'freechal.com',
|
||||
'empas.com',
|
||||
'empal.com',
|
||||
'hanafos.com',
|
||||
);
|
||||
|
||||
/**
|
||||
* Domains known to be foreign.
|
||||
*/
|
||||
public static $known_foreign = array(
|
||||
'gmail.com',
|
||||
'googlemail.com',
|
||||
'google.com',
|
||||
'yahoo.com',
|
||||
'yahoo.co.kr',
|
||||
'hotmail.com',
|
||||
'hotmail.co.kr',
|
||||
'live.com',
|
||||
'outlook.com',
|
||||
'msn.com',
|
||||
'me.com',
|
||||
'mac.com',
|
||||
'icloud.com',
|
||||
'facebook.com',
|
||||
'aol.com',
|
||||
'gmx.com',
|
||||
'mail.com',
|
||||
'fastmail.com',
|
||||
'fastmail.fm',
|
||||
'runbox.com',
|
||||
'inbox.com',
|
||||
'lycos.com',
|
||||
'zoho.com',
|
||||
);
|
||||
}
|
||||
|
|
@ -75,19 +75,19 @@ class Lang
|
|||
|
||||
if ($name === 'common')
|
||||
{
|
||||
$this->loadDirectory(RX_BASEDIR . 'common/lang', 'common');
|
||||
$this->loadDirectory(\RX_BASEDIR . 'common/lang', 'common');
|
||||
}
|
||||
elseif (file_exists(RX_BASEDIR . "plugins/$name/lang"))
|
||||
elseif (file_exists(\RX_BASEDIR . "plugins/$name/lang"))
|
||||
{
|
||||
$this->loadDirectory(RX_BASEDIR . "plugins/$name/lang", $name);
|
||||
$this->loadDirectory(\RX_BASEDIR . "plugins/$name/lang", $name);
|
||||
}
|
||||
elseif (file_exists(RX_BASEDIR . "modules/$name/lang"))
|
||||
elseif (file_exists(\RX_BASEDIR . "modules/$name/lang"))
|
||||
{
|
||||
$this->loadDirectory(RX_BASEDIR . "modules/$name/lang", $name);
|
||||
$this->loadDirectory(\RX_BASEDIR . "modules/$name/lang", $name);
|
||||
}
|
||||
elseif (file_exists(RX_BASEDIR . "addons/$name/lang"))
|
||||
elseif (file_exists(\RX_BASEDIR . "addons/$name/lang"))
|
||||
{
|
||||
$this->loadDirectory(RX_BASEDIR . "addons/$name/lang", $name);
|
||||
$this->loadDirectory(\RX_BASEDIR . "addons/$name/lang", $name);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -163,7 +163,7 @@ class Lang
|
|||
*/
|
||||
public static function getSupportedList()
|
||||
{
|
||||
return (include RX_BASEDIR . 'common/defaults/lang.php');
|
||||
return (include \RX_BASEDIR . 'common/defaults/lang.php');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
152
common/framework/mime.php
Normal file
152
common/framework/mime.php
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
<?php
|
||||
|
||||
namespace Rhymix\Framework;
|
||||
|
||||
/**
|
||||
* The MIME class.
|
||||
*/
|
||||
class MIME
|
||||
{
|
||||
/**
|
||||
* Get the MIME type for the given extension.
|
||||
*
|
||||
* @param string $extension
|
||||
* @return string
|
||||
*/
|
||||
public static function getTypeByExtension($extension)
|
||||
{
|
||||
$extension = strtolower($extension);
|
||||
return array_key_exists($extension, self::$_types) ? self::$_types[$extension] : self::$_default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the MIME type for the given filename.
|
||||
*
|
||||
* @param string $filename
|
||||
* @return string
|
||||
*/
|
||||
public static function getTypeByFilename($filename)
|
||||
{
|
||||
$extension = strrchr($filename, '.');
|
||||
if ($extension === false) return self::$_default;
|
||||
$extension = strtolower(substr($extension, 1));
|
||||
return array_key_exists($extension, self::$_types) ? self::$_types[$extension] : self::$_default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the most common extension for the given MIME type.
|
||||
*
|
||||
* @param string $type
|
||||
* @return string|false
|
||||
*/
|
||||
public static function getExtensionByType($type)
|
||||
{
|
||||
foreach (self::$_types as $extension => $mime)
|
||||
{
|
||||
if (!strncasecmp($type, $mime, strlen($type))) return $extension;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* The default MIME type for unknown extensions.
|
||||
*/
|
||||
protected static $_default = 'application/octet-stream';
|
||||
|
||||
/**
|
||||
* The list of known MIME types.
|
||||
*/
|
||||
protected static $_types = array(
|
||||
|
||||
// Text-based document formats.
|
||||
'html' => 'text/html',
|
||||
'htm' => 'text/html',
|
||||
'shtml' => 'text/html',
|
||||
'txt' => 'text/plain',
|
||||
'text' => 'text/plain',
|
||||
'log' => 'text/plain',
|
||||
'rtf' => 'text/rtf',
|
||||
'xml' => 'text/xml',
|
||||
'xsl' => 'text/xml',
|
||||
'css' => 'text/css',
|
||||
'csv' => 'text/csv',
|
||||
|
||||
// Binary document formats.
|
||||
'doc' => 'application/msword',
|
||||
'dot' => 'application/msword',
|
||||
'xls' => 'application/vnd.ms-excel',
|
||||
'ppt' => 'application/vnd.ms-powerpoint',
|
||||
'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||
'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||
'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
||||
'odt' => 'application/vnd.oasis.opendocument.text',
|
||||
'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
|
||||
'odp' => 'application/vnd.oasis.opendocument.presentation',
|
||||
'odg' => 'application/vnd.oasis.opendocument.graphics',
|
||||
'odb' => 'application/vnd.oasis.opendocument.database',
|
||||
'pdf' => 'application/pdf',
|
||||
|
||||
// Images.
|
||||
'bmp' => 'image/bmp',
|
||||
'gif' => 'image/gif',
|
||||
'jpg' => 'image/jpeg',
|
||||
'jpeg' => 'image/jpeg',
|
||||
'jpe' => 'image/jpeg',
|
||||
'png' => 'image/png',
|
||||
'svg' => 'image/svg+xml',
|
||||
'tiff' => 'image/tiff',
|
||||
'tif' => 'image/tiff',
|
||||
'ico' => 'image/vnd.microsoft.icon',
|
||||
|
||||
// Audio.
|
||||
'mid' => 'audio/midi',
|
||||
'midi' => 'audio/midi',
|
||||
'mpga' => 'audio/mpeg',
|
||||
'mp2' => 'audio/mpeg',
|
||||
'mp3' => 'audio/mpeg',
|
||||
'aif' => 'audio/x-aiff',
|
||||
'aiff' => 'audio/x-aiff',
|
||||
'ra' => 'audio/x-realaudio',
|
||||
'wav' => 'audio/x-wav',
|
||||
'ogg' => 'audio/ogg',
|
||||
|
||||
// Video.
|
||||
'avi' => 'video/x-msvideo',
|
||||
'flv' => 'video/x-flv',
|
||||
'mpeg' => 'video/mpeg',
|
||||
'mpg' => 'video/mpeg',
|
||||
'mpe' => 'video/mpeg',
|
||||
'mp4' => 'video/mpeg',
|
||||
'qt' => 'video/quicktime',
|
||||
'mov' => 'video/quicktime',
|
||||
'movie' => 'video/x-sgi-movie',
|
||||
'rv' => 'video/vnd.rn-realvideo',
|
||||
'dvi' => 'application/x-dvi',
|
||||
|
||||
// Other multimedia file formats.
|
||||
'psd' => 'application/x-photoshop',
|
||||
'swf' => 'application/x-shockwave-flash',
|
||||
'ai' => 'application/postscript',
|
||||
'eps' => 'application/postscript',
|
||||
'ps' => 'application/postscript',
|
||||
'mif' => 'application/vnd.mif',
|
||||
'xul' => 'application/vnd.mozilla.xul+xml',
|
||||
|
||||
// Source code formats.
|
||||
'phps' => 'application/x-httpd-php-source',
|
||||
'js' => 'application/x-javascript',
|
||||
|
||||
// Archives.
|
||||
'bz2' => 'application/x-bzip',
|
||||
'gz' => 'application/x-gzip',
|
||||
'tar' => 'application/x-tar',
|
||||
'tgz' => 'application/x-tar',
|
||||
'gtar' => 'application/x-gtar',
|
||||
'rar' => 'application/x-rar-compressed',
|
||||
'zip' => 'application/x-zip',
|
||||
|
||||
// RFC822 email message.
|
||||
'eml' => 'message/rfc822',
|
||||
);
|
||||
}
|
||||
153
common/framework/pagination.php
Normal file
153
common/framework/pagination.php
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
<?php
|
||||
|
||||
namespace Rhymix\Framework;
|
||||
|
||||
/**
|
||||
* The pagination class.
|
||||
*/
|
||||
class Pagination
|
||||
{
|
||||
/**
|
||||
* Count style constants.
|
||||
*/
|
||||
const COUNT_STYLE_NORMAL = 1;
|
||||
const COUNT_STYLE_CONTINUOUS = 2;
|
||||
|
||||
/**
|
||||
* Calculate the number of pages.
|
||||
*
|
||||
* @param int $total_items
|
||||
* @param int $items_per_page
|
||||
* @param int $minimum (optional)
|
||||
* @return int
|
||||
*/
|
||||
public static function countPages($total_items, $items_per_page, $minimum = 1)
|
||||
{
|
||||
if (!$items_per_page)
|
||||
{
|
||||
return (int)$minimum;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (int)max($minimum, ceil($total_items / $items_per_page));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create HTML for pagination.
|
||||
*
|
||||
* @param string $base_url ($PAGE will be replaced with the page number)
|
||||
* @param int $current_page
|
||||
* @param int $total_pages
|
||||
* @param int $count (optional)
|
||||
*/
|
||||
public static function createLinks($base_url, $total_pages, $current_page, $count = 10, $count_style = self::COUNT_STYLE_NORMAL)
|
||||
{
|
||||
// Only integers are allowed here.
|
||||
$current_page = (int)$current_page;
|
||||
$total_pages = (int)$total_pages;
|
||||
$count = (int)$count;
|
||||
|
||||
// Determine the range of pages to show.
|
||||
if ($count_style === self::COUNT_STYLE_NORMAL)
|
||||
{
|
||||
$last_shown = ceil($current_page / $count) * $count;
|
||||
$first_shown = max(1, $last_shown - $count + 1);
|
||||
if ($last_shown > $total_pages)
|
||||
{
|
||||
$last_shown = $total_pages;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$first_shown = $current_page - floor(($count - 1) / 2);
|
||||
if ($first_shown < 1)
|
||||
{
|
||||
$first_shown = 1;
|
||||
}
|
||||
$last_shown = $first_shown + $count - 1;
|
||||
if ($last_shown > $total_pages)
|
||||
{
|
||||
$last_shown = $total_pages;
|
||||
$first_shown = max(1, $last_shown - $count + 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Open the <div> tag.
|
||||
$return = array('<div class="pagination">');
|
||||
|
||||
// Compose the link to the first page.
|
||||
if ($first_shown > 1)
|
||||
{
|
||||
if (strpos($base_url, '$PAGE') !== false)
|
||||
{
|
||||
$target_url = str_replace('$PAGE', 1, $base_url);
|
||||
}
|
||||
else
|
||||
{
|
||||
$target_url = $base_url . 1;
|
||||
}
|
||||
|
||||
$return[] = self::_composeLink($target_url, '<span class="arrow">«</span> <span class="page_number first_page">1</span>');
|
||||
$return[] = '<span class="ellipsis">...</span>';
|
||||
}
|
||||
|
||||
// Compose links for each page.
|
||||
for ($page = $first_shown; $page <= $last_shown; $page++)
|
||||
{
|
||||
if ($page == $current_page)
|
||||
{
|
||||
$opening_span = '<span class="page_number current_page">';
|
||||
}
|
||||
else
|
||||
{
|
||||
$opening_span = '<span class="page_number">';
|
||||
}
|
||||
|
||||
if (strpos($base_url, '$PAGE') !== false)
|
||||
{
|
||||
$target_url = str_replace('$PAGE', $page, $base_url);
|
||||
}
|
||||
else
|
||||
{
|
||||
$target_url = $base_url . $page;
|
||||
}
|
||||
|
||||
$return[] = self::_composeLink($target_url, $opening_span . $page . '</span>');
|
||||
}
|
||||
|
||||
// Compose the link to the last page.
|
||||
if ($last_shown < $total_pages)
|
||||
{
|
||||
if (strpos($base_url, '$PAGE') !== false)
|
||||
{
|
||||
$target_url = str_replace('$PAGE', $total_pages, $base_url);
|
||||
}
|
||||
else
|
||||
{
|
||||
$target_url = $base_url . $total_pages;
|
||||
}
|
||||
|
||||
$return[] = '<span class="ellipsis">...</span>';
|
||||
$return[] = self::_composeLink($target_url, '<span class="page_number last_page">' . $total_pages . '</span> <span class="arrow">»</span>');
|
||||
}
|
||||
|
||||
// Close the <div> tag.
|
||||
$return[] = '</div>';
|
||||
|
||||
// Return the completed HTML.
|
||||
return implode(' ', $return);
|
||||
}
|
||||
|
||||
/**
|
||||
* Link creation subroutine.
|
||||
*
|
||||
* @param string $target_url
|
||||
* @param string $content
|
||||
* @return string
|
||||
*/
|
||||
protected static function _composeLink($target_url, $content)
|
||||
{
|
||||
return '<a href="' . escape($target_url) . '">' . $content . '</a>';
|
||||
}
|
||||
}
|
||||
|
|
@ -19,9 +19,9 @@ class ConfigParser
|
|||
public static function convert()
|
||||
{
|
||||
// Load DB info file.
|
||||
if (file_exists(RX_BASEDIR . Config::$old_db_config_filename))
|
||||
if (file_exists(\RX_BASEDIR . Config::$old_db_config_filename))
|
||||
{
|
||||
include RX_BASEDIR . Config::$old_db_config_filename;
|
||||
include \RX_BASEDIR . Config::$old_db_config_filename;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -29,16 +29,16 @@ class ConfigParser
|
|||
}
|
||||
|
||||
// Load FTP info file.
|
||||
if (file_exists(RX_BASEDIR . Config::$old_ftp_config_filename))
|
||||
if (file_exists(\RX_BASEDIR . Config::$old_ftp_config_filename))
|
||||
{
|
||||
include RX_BASEDIR . Config::$old_ftp_config_filename;
|
||||
include \RX_BASEDIR . Config::$old_ftp_config_filename;
|
||||
}
|
||||
|
||||
// Load selected language file.
|
||||
if (file_exists(RX_BASEDIR . Config::$old_lang_config_filename))
|
||||
if (file_exists(\RX_BASEDIR . Config::$old_lang_config_filename))
|
||||
{
|
||||
$lang_selected = array();
|
||||
$lang_selected_raw = file_get_contents(RX_BASEDIR . Config::$old_lang_config_filename);
|
||||
$lang_selected_raw = file_get_contents(\RX_BASEDIR . Config::$old_lang_config_filename);
|
||||
$lang_selected_raw = array_map('trim', explode("\n", $lang_selected_raw));
|
||||
foreach ($lang_selected_raw as $lang_selected_item)
|
||||
{
|
||||
|
|
@ -59,7 +59,7 @@ class ConfigParser
|
|||
}
|
||||
|
||||
// Load defaults for the new configuration.
|
||||
$config = (include RX_BASEDIR . Config::$default_config_filename);
|
||||
$config = (include \RX_BASEDIR . Config::$default_config_filename);
|
||||
|
||||
// Convert database configuration.
|
||||
if (!isset($db_info->master_db))
|
||||
|
|
@ -184,7 +184,7 @@ class ConfigParser
|
|||
{
|
||||
$default_url = \Context::decodeIdna($default_url);
|
||||
}
|
||||
$config['url']['default'] = $default_url ?: (RX_SSL ? 'https://' : 'http://') . $_SERVER['HTTP_HOST'] . \RX_BASEURL;
|
||||
$config['url']['default'] = $default_url ?: (\RX_SSL ? 'https://' : 'http://') . $_SERVER['HTTP_HOST'] . \RX_BASEURL;
|
||||
$config['url']['http_port'] = $db_info->http_port ?: null;
|
||||
$config['url']['https_port'] = $db_info->https_port ?: null;
|
||||
$config['url']['ssl'] = $db_info->use_ssl ?: 'none';
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
namespace Rhymix\Framework\Parsers;
|
||||
|
||||
use Rhymix\Framework\Lang;
|
||||
use Rhymix\Framework\Storage;
|
||||
|
||||
/**
|
||||
* Lang parser class for XE compatibility.
|
||||
|
|
@ -32,7 +33,7 @@ class LangParser
|
|||
foreach ($files as $filename)
|
||||
{
|
||||
$new_filename = preg_replace('/\.lang\.php$/', '.php', str_replace('jp.lang', 'ja.lang', $filename));
|
||||
\FileHandler::rename($filename, $new_filename);
|
||||
Storage::move($filename, $new_filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -49,7 +50,7 @@ class LangParser
|
|||
// Check if the cache file already exists.
|
||||
if ($output_filename === null)
|
||||
{
|
||||
$output_filename = RX_BASEDIR . 'files/cache/lang/' . md5($filename) . '.' . $language . '.php';
|
||||
$output_filename = \RX_BASEDIR . 'files/cache/lang/' . md5($filename) . '.' . $language . '.php';
|
||||
if (file_exists($output_filename) && filemtime($output_filename) > filemtime($filename))
|
||||
{
|
||||
return $output_filename;
|
||||
|
|
@ -60,7 +61,7 @@ class LangParser
|
|||
$xml = @simplexml_load_file($filename);
|
||||
if ($xml === false)
|
||||
{
|
||||
\FileHandler::writeFile($output_filename, '');
|
||||
Storage::write($output_filename, '');
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -95,7 +96,7 @@ class LangParser
|
|||
$buff .= '$lang->' . $key . ' = ' . var_export($value, true) . ";\n";
|
||||
}
|
||||
}
|
||||
\FileHandler::writeFile($output_filename, $buff);
|
||||
Storage::write($output_filename, $buff);
|
||||
return $output_filename;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,5 +7,476 @@ namespace Rhymix\Framework;
|
|||
*/
|
||||
class Storage
|
||||
{
|
||||
/**
|
||||
* Check if a path really exists.
|
||||
*
|
||||
* @param string $path
|
||||
* @return bool
|
||||
*/
|
||||
public static function exists($path)
|
||||
{
|
||||
$path = rtrim($path, '/\\');
|
||||
clearstatcache(true, $path);
|
||||
return @file_exists($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given path is a file.
|
||||
*
|
||||
* @param string $path
|
||||
* @return bool
|
||||
*/
|
||||
public static function isFile($path)
|
||||
{
|
||||
$path = rtrim($path, '/\\');
|
||||
return @self::exists($path) && @is_file($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given path is an empty file.
|
||||
*
|
||||
* @param string $path
|
||||
* @return bool
|
||||
*/
|
||||
public static function isEmptyFile($path)
|
||||
{
|
||||
$path = rtrim($path, '/\\');
|
||||
return @self::exists($path) && @is_file($path) && (@filesize($path) == 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if the given path is a directory.
|
||||
*
|
||||
* @param string $path
|
||||
* @return bool
|
||||
*/
|
||||
public static function isDirectory($path)
|
||||
{
|
||||
$path = rtrim($path, '/\\');
|
||||
return @self::exists($path) && @is_dir($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given path is an empty directory.
|
||||
*
|
||||
* @param string $path
|
||||
* @return bool
|
||||
*/
|
||||
public static function isEmptyDirectory($path)
|
||||
{
|
||||
$path = rtrim($path, '/\\');
|
||||
if (!self::isDirectory($path))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$iterator = new \FilesystemIterator($path, \FilesystemIterator::SKIP_DOTS);
|
||||
return (iterator_count($iterator)) === 0 ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given path is a symbolic link.
|
||||
*
|
||||
* @param string $path
|
||||
* @return bool
|
||||
*/
|
||||
public static function isSymlink($path)
|
||||
{
|
||||
$path = rtrim($path, '/\\');
|
||||
return @is_link($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given path is a valid symbolic link.
|
||||
*
|
||||
* @param string $path
|
||||
* @return bool
|
||||
*/
|
||||
public static function isValidSymlink($path)
|
||||
{
|
||||
$path = rtrim($path, '/\\');
|
||||
return @is_link($path) && ($target = @readlink($path)) !== false && self::exists($target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given path is readable.
|
||||
*
|
||||
* @param string $path
|
||||
* @return bool
|
||||
*/
|
||||
public static function isReadable($path)
|
||||
{
|
||||
$path = rtrim($path, '/\\');
|
||||
return @self::exists($path) && @is_readable($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given path is writable.
|
||||
*
|
||||
* @param string $path
|
||||
* @return bool
|
||||
*/
|
||||
public static function isWritable($path)
|
||||
{
|
||||
$path = rtrim($path, '/\\');
|
||||
return @self::exists($path) && @is_writable($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the size of a file.
|
||||
*
|
||||
* This method returns the size of a file, or false on error.
|
||||
*
|
||||
* @param string $filename
|
||||
* @return int|false
|
||||
*/
|
||||
public static function getSize($filename)
|
||||
{
|
||||
$filename = rtrim($filename, '/\\');
|
||||
if (self::exists($filename) && @is_file($filename) && @is_readable($filename))
|
||||
{
|
||||
return @filesize($filename);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the content of a file.
|
||||
*
|
||||
* This method returns the content if it exists and is readable.
|
||||
* Otherwise, it returns false.
|
||||
*
|
||||
* @param string $filename
|
||||
* @return string|false
|
||||
*/
|
||||
public static function read($filename)
|
||||
{
|
||||
$filename = rtrim($filename, '/\\');
|
||||
if (self::exists($filename) && @is_file($filename) && @is_readable($filename))
|
||||
{
|
||||
return @file_get_contents($filename);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write $content to a file.
|
||||
*
|
||||
* This method returns true on success and false on failure.
|
||||
*
|
||||
* @param string $filename
|
||||
* @param string $content
|
||||
* @param string $mode (optional)
|
||||
* @param int $perms (optional)
|
||||
* @return string|false
|
||||
*/
|
||||
public static function write($filename, $content, $mode = 'w', $perms = null)
|
||||
{
|
||||
$filename = rtrim($filename, '/\\');
|
||||
$destination_dir = dirname($filename);
|
||||
if (!self::exists($destination_dir))
|
||||
{
|
||||
$mkdir_success = self::createDirectory($destination_dir);
|
||||
if (!$mkdir_success)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$flags = ($mode === 'a') ? (\FILE_APPEND | \LOCK_EX) : (\LOCK_EX);
|
||||
$write_success = @file_put_contents($filename, $content, $flags);
|
||||
$result = ($write_success === strlen($content)) ? true : false;
|
||||
@chmod($filename, ($perms === null ? (0666 & ~umask()) : $perms));
|
||||
if (function_exists('opcache_invalidate') && substr($filename, -4) === '.php')
|
||||
{
|
||||
@opcache_invalidate($filename, true);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy $source to $destination.
|
||||
*
|
||||
* This method returns true on success and false on failure.
|
||||
* If the destination permissions are not given, they will be copied from the source.
|
||||
*
|
||||
* @param string $source
|
||||
* @param string $destination
|
||||
* @param int $destination_perms
|
||||
* @return bool
|
||||
*/
|
||||
public static function copy($source, $destination, $destination_perms = null)
|
||||
{
|
||||
$source = rtrim($source, '/\\');
|
||||
$destination = rtrim($destination, '/\\');
|
||||
if (!self::exists($source))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$destination_dir = dirname($destination);
|
||||
if (!self::exists($destination_dir) && !self::createDirectory($destination_dir))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
elseif (self::isDirectory($destination))
|
||||
{
|
||||
$destination = $destination . '/' . basename($source);
|
||||
}
|
||||
|
||||
$copy_success = @copy($source, $destination);
|
||||
if (!$copy_success)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($destination_perms === null)
|
||||
{
|
||||
@chmod($destination, 0777 & @fileperms($source));
|
||||
}
|
||||
else
|
||||
{
|
||||
@chmod($destination, $destination_perms);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move $source to $destination.
|
||||
*
|
||||
* This method returns true on success and false on failure.
|
||||
*
|
||||
* @param string $source
|
||||
* @param string $destination
|
||||
* @return bool
|
||||
*/
|
||||
public static function move($source, $destination)
|
||||
{
|
||||
$source = rtrim($source, '/\\');
|
||||
$destination = rtrim($destination, '/\\');
|
||||
if (!self::exists($source))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$destination_dir = dirname($destination);
|
||||
if (!self::exists($destination_dir) && !self::createDirectory($destination_dir))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
elseif (self::isDirectory($destination))
|
||||
{
|
||||
$destination = $destination . '/' . basename($source);
|
||||
}
|
||||
|
||||
$result = @rename($source, $destination);
|
||||
if (function_exists('opcache_invalidate') && substr($source, -4) === '.php')
|
||||
{
|
||||
@opcache_invalidate($source, true);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a file.
|
||||
*
|
||||
* This method returns true if the file exists and has been successfully
|
||||
* deleted, and false on any kind of failure.
|
||||
*
|
||||
* @param string $filename
|
||||
* @return bool
|
||||
*/
|
||||
public static function delete($filename)
|
||||
{
|
||||
$filename = rtrim($filename, '/\\');
|
||||
$result = @self::exists($filename) && @is_file($filename) && @unlink($filename);
|
||||
if (function_exists('opcache_invalidate') && substr($filename, -4) === '.php')
|
||||
{
|
||||
@opcache_invalidate($filename, true);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a directory.
|
||||
*
|
||||
* @param string $dirname
|
||||
* @return bool
|
||||
*/
|
||||
public static function createDirectory($dirname, $mode = null)
|
||||
{
|
||||
$dirname = rtrim($dirname, '/\\');
|
||||
if ($mode === null)
|
||||
{
|
||||
$mode = 0777 & ~umask();
|
||||
}
|
||||
return @mkdir($dirname, $mode, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the list of files in a directory.
|
||||
*
|
||||
* @param string $dirname
|
||||
* @param bool $full_path (optional)
|
||||
* @param bool $skip_dotfiles (optional)
|
||||
* @param bool $skip_subdirs (optional)
|
||||
* @return array|false
|
||||
*/
|
||||
public static function readDirectory($dirname, $full_path = true, $skip_dotfiles = true, $skip_subdirs = true)
|
||||
{
|
||||
$dirname = rtrim($dirname, '/\\');
|
||||
if (!self::isDirectory($dirname))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$iterator = new \FilesystemIterator($dirname, \FilesystemIterator::CURRENT_AS_PATHNAME);
|
||||
}
|
||||
catch (\UnexpectedValueException $e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$result = array();
|
||||
foreach ($iterator as $fileinfo)
|
||||
{
|
||||
if (!$skip_subdirs || !is_dir($fileinfo))
|
||||
{
|
||||
$basename = basename($fileinfo);
|
||||
if (!$skip_dotfiles || $basename[0] !== '.')
|
||||
{
|
||||
$result[] = $full_path ? $fileinfo : $basename;
|
||||
}
|
||||
}
|
||||
}
|
||||
sort($result);
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy a directory recursively.
|
||||
*
|
||||
* @param string $source
|
||||
* @param string $destination
|
||||
* @param string $exclude_regexp (optional)
|
||||
* @return bool
|
||||
*/
|
||||
public static function copyDirectory($source, $destination, $exclude_regexp = null)
|
||||
{
|
||||
$source = rtrim($source, '/\\');
|
||||
$destination = rtrim($destination, '/\\');
|
||||
if (!self::isDirectory($source))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!self::isDirectory($destination) && !self::createDirectory($destination))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$rdi_options = \FilesystemIterator::KEY_AS_PATHNAME | \FilesystemIterator::CURRENT_AS_FILEINFO | \FilesystemIterator::SKIP_DOTS;
|
||||
$rii_options = \RecursiveIteratorIterator::CHILD_FIRST;
|
||||
$iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($source, $rdi_options), $rii_options);
|
||||
|
||||
foreach ($iterator as $path)
|
||||
{
|
||||
$path_source = $path->getPathname();
|
||||
if (strpos($path_source, $source) !== 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if ($exclude_regexp && preg_match($exclude_regexp, $path_source))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$path_destination = $destination . substr($path_source, strlen($source));
|
||||
if ($path->isDir())
|
||||
{
|
||||
$status = self::isDirectory($path_destination) || self::createDirectory($path_destination, $path->getPerms());
|
||||
if (!$status)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$status = self::copy($path_source, $path_destination, $path->getPerms());
|
||||
if (!$status)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move a directory.
|
||||
*
|
||||
* @param string $source
|
||||
* @param string $destination
|
||||
* @return bool
|
||||
*/
|
||||
public static function moveDirectory($source, $destination)
|
||||
{
|
||||
return self::move($source, $destination);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a directory recursively.
|
||||
*
|
||||
* @param string $dirname
|
||||
* @param bool $delete_self (optional)
|
||||
* @return bool
|
||||
*/
|
||||
public static function deleteDirectory($dirname, $delete_self = true)
|
||||
{
|
||||
$dirname = rtrim($dirname, '/\\');
|
||||
if (!self::isDirectory($dirname))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$rdi_options = \FilesystemIterator::KEY_AS_PATHNAME | \FilesystemIterator::CURRENT_AS_FILEINFO | \FilesystemIterator::SKIP_DOTS;
|
||||
$rii_options = \RecursiveIteratorIterator::CHILD_FIRST;
|
||||
$iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($dirname, $rdi_options), $rii_options);
|
||||
|
||||
foreach ($iterator as $path)
|
||||
{
|
||||
if ($path->isDir())
|
||||
{
|
||||
if (!@rmdir($path->getPathname()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!@unlink($path->getPathname()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($delete_self)
|
||||
{
|
||||
return @rmdir($dirname);
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
109
common/framework/timer.php
Normal file
109
common/framework/timer.php
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
<?php
|
||||
|
||||
namespace Rhymix\Framework;
|
||||
|
||||
/**
|
||||
* The timer class.
|
||||
*/
|
||||
class Timer
|
||||
{
|
||||
/**
|
||||
* Timestamps are stored here.
|
||||
*/
|
||||
protected static $_timestamps = array();
|
||||
|
||||
/**
|
||||
* Start a timer.
|
||||
*
|
||||
* This method returns the current microtime.
|
||||
*
|
||||
* @param string $name (optional)
|
||||
* @return float
|
||||
*/
|
||||
public static function start($name = null)
|
||||
{
|
||||
$timestamp = microtime(true);
|
||||
|
||||
if ($name === null)
|
||||
{
|
||||
$name = 'anon-timer-' . $timestamp;
|
||||
}
|
||||
|
||||
self::$_timestamps[$name] = $timestamp;
|
||||
return $timestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop a timer and return the elapsed time.
|
||||
*
|
||||
* If the name is not given, the most recently started timer will be stopped.
|
||||
* If no timer has been started, this method returns false.
|
||||
*
|
||||
* @param string $name (optional)
|
||||
* @return float|false
|
||||
*/
|
||||
public static function stop($name = null)
|
||||
{
|
||||
$timestamp = microtime(true);
|
||||
$started_timestamp = 0;
|
||||
|
||||
if ($name === null)
|
||||
{
|
||||
if (count(self::$_timestamps))
|
||||
{
|
||||
$started_timestamp = array_pop(self::$_timestamps);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
elseif (array_key_exists($name, self::$_timestamps))
|
||||
{
|
||||
$started_timestamp = self::$_timestamps[$name];
|
||||
unset(self::$_timestamps[$name]);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return $timestamp - $started_timestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop a timer and return the elapsed time in a human-readable format.
|
||||
*
|
||||
* If the name is not given, the most recently started timer will be stopped.
|
||||
* If no timer has been started, this method returns false.
|
||||
*
|
||||
* @param string $name (optional)
|
||||
* @return string|false
|
||||
*/
|
||||
public static function stopFormat($name = null)
|
||||
{
|
||||
$result = self::stop($name);
|
||||
if ($result === false) return $result;
|
||||
return number_format($result * 1000, 1, '.', ',') . 'ms';
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns how much time has elapsed since Rhymix startup.
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function sinceStartup()
|
||||
{
|
||||
return microtime(true) - \RX_MICROTIME;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns how much time has elapsed since startup in a human-readable format.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function sinceStartupFormat()
|
||||
{
|
||||
return number_format((microtime(true) - \RX_MICROTIME) * 1000, 1, '.', ',') . 'ms';
|
||||
}
|
||||
}
|
||||
240
common/framework/ua.php
Normal file
240
common/framework/ua.php
Normal file
|
|
@ -0,0 +1,240 @@
|
|||
<?php
|
||||
|
||||
namespace Rhymix\Framework;
|
||||
|
||||
/**
|
||||
* The user-agent class.
|
||||
*/
|
||||
class UA
|
||||
{
|
||||
/**
|
||||
* Cache to prevent multiple lookups.
|
||||
*/
|
||||
protected static $_mobile_cache = array();
|
||||
protected static $_tablet_cache = array();
|
||||
protected static $_robot_cache = array();
|
||||
|
||||
/**
|
||||
* Check whether the current visitor is using a mobile device.
|
||||
*
|
||||
* @param string $ua (optional)
|
||||
* @return bool
|
||||
*/
|
||||
public static function isMobile($ua = null)
|
||||
{
|
||||
// Get the User-Agent header if the caller did not specify $ua.
|
||||
if ($ua === null)
|
||||
{
|
||||
$ua = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : null;
|
||||
$using_header = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$using_header = false;
|
||||
}
|
||||
|
||||
// If the User-Agent header is missing, it's probably not a mobile browser.
|
||||
if (is_null($ua))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Look for headers that are only used in mobile browsers.
|
||||
if ($using_header && (isset($_SERVER['HTTP_X_WAP_PROFILE']) || isset($_SERVER['HTTP_X_OPERAMINI_PHONE_UA'])))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Look up the cache.
|
||||
if (isset(self::$_mobile_cache[$ua]))
|
||||
{
|
||||
return self::$_mobile_cache[$ua];
|
||||
}
|
||||
|
||||
// Look for the 'mobile' keyword and common mobile platform names.
|
||||
if (preg_match('/android|ip(hone|ad|od)|blackberry|nokia|palm|mobile/i', $ua))
|
||||
{
|
||||
return self::$_mobile_cache[$ua] = true;
|
||||
}
|
||||
|
||||
// Look for common non-mobile OS names.
|
||||
if (preg_match('/windows|linux|os [x9]|bsd/i', $ua))
|
||||
{
|
||||
return self::$_mobile_cache[$ua] = false;
|
||||
}
|
||||
|
||||
// Look for other platform, manufacturer, and device names that are known to be mobile.
|
||||
if (preg_match('/kindle|opera (mini|mobi)|polaris|netfront|fennec|motorola|symbianos|webos/i', $ua))
|
||||
{
|
||||
return self::$_mobile_cache[$ua] = true;
|
||||
}
|
||||
if (preg_match('/s[pgc]h-|lgtelecom|sonyericsson|alcatel|vodafone|maemo|minimo|bada/i', $ua))
|
||||
{
|
||||
return self::$_mobile_cache[$ua] = true;
|
||||
}
|
||||
|
||||
// If we're here, it's probably not a mobile device.
|
||||
return self::$_mobile_cache[$ua] = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the current visitor is using a tablet.
|
||||
*
|
||||
* @param string $ua (optional)
|
||||
* @return bool
|
||||
*/
|
||||
public static function isTablet($ua = null)
|
||||
{
|
||||
// Get the User-Agent header if the caller did not specify $ua.
|
||||
$ua = $ua ?: (isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : null);
|
||||
|
||||
// If the User-Agent header is missing, it's probably not a tablet.
|
||||
if (is_null($ua))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Look up the cache.
|
||||
if (isset(self::$_tablet_cache[$ua]))
|
||||
{
|
||||
return self::$_tablet_cache[$ua];
|
||||
}
|
||||
|
||||
// Check if the user-agent is mobile.
|
||||
if (!self::isMobile($ua))
|
||||
{
|
||||
return self::$_tablet_cache[$ua] = false;
|
||||
}
|
||||
|
||||
// Check for Android tablets without the 'mobile' keyword.
|
||||
if (stripos($ua, 'android') !== false && stripos($ua, 'mobile') === false)
|
||||
{
|
||||
return self::$_tablet_cache[$ua] = true;
|
||||
}
|
||||
|
||||
// Check for common tablet identifiers.
|
||||
if (preg_match('/tablet|pad\b|tab\b|\bgt-\d+|kindle|nook|playbook|webos|xoom/i', $ua))
|
||||
{
|
||||
return self::$_tablet_cache[$ua] = true;
|
||||
}
|
||||
|
||||
// If we're here, it's probably not a tablet.
|
||||
return self::$_tablet_cache[$ua] = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the current visitor is a robot.
|
||||
*
|
||||
* @param string $ua (optional)
|
||||
* @return bool
|
||||
*/
|
||||
public static function isRobot($ua = null)
|
||||
{
|
||||
// Get the User-Agent header if the caller did not specify $ua.
|
||||
$ua = $ua ?: (isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : null);
|
||||
|
||||
// If the User-Agent header is missing, it's probably not a robot.
|
||||
if (is_null($ua))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Look up the cache.
|
||||
if (isset(self::$_robot_cache[$ua]))
|
||||
{
|
||||
return self::$_robot_cache[$ua];
|
||||
}
|
||||
|
||||
// Look for common search engine names and the 'bot' keyword.
|
||||
if (preg_match('/bot|slurp|facebook(externalhit|scraper)|ia_archiver|ask jeeves|teoma|baidu|daumoa|lycos|pingdom/i', $ua))
|
||||
{
|
||||
return self::$_robot_cache[$ua] = true;
|
||||
}
|
||||
|
||||
// If we're here, it's probably not a robot.
|
||||
return self::$_robot_cache[$ua] = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method parses the User-Agent string to guess what kind of browser it is.
|
||||
*
|
||||
* @param string $ua (optional)
|
||||
* @return object
|
||||
*/
|
||||
public static function getBrowserInfo($ua = null)
|
||||
{
|
||||
// Get the User-Agent header if the caller did not specify $ua.
|
||||
$ua = $ua ?: (isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : null);
|
||||
|
||||
// Initialize the result.
|
||||
$result = (object)array(
|
||||
'browser' => null,
|
||||
'version' => null,
|
||||
'os' => null,
|
||||
'is_mobile' => null,
|
||||
'is_tablet' => null,
|
||||
);
|
||||
if (is_null($ua))
|
||||
{
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Try to guess the OS.
|
||||
if (preg_match('#(Windows|Android|Linux|iOS|OS X|Macintosh)#i', $ua, $matches))
|
||||
{
|
||||
if ($matches[1] === 'Linux' && strpos($ua, 'Android') !== false)
|
||||
{
|
||||
$matches[1] = 'Android';
|
||||
}
|
||||
if ($matches[1] === 'Macintosh' && strpos($ua, 'OS X') !== false)
|
||||
{
|
||||
$matches[1] = 'OS X';
|
||||
}
|
||||
$result->os = $matches[1];
|
||||
}
|
||||
|
||||
// Fill in miscellaneous fields.
|
||||
$result->is_mobile = self::isMobile($ua);
|
||||
$result->is_tablet = self::isTablet($ua);
|
||||
|
||||
// Try to match some of the most common browsers.
|
||||
if (preg_match('#Android ([0-9]+\\.[0-9]+)#', $ua, $matches) && strpos($ua, 'Chrome') === false)
|
||||
{
|
||||
$result->browser = 'Android';
|
||||
$result->version = $matches[1];
|
||||
return $result;
|
||||
}
|
||||
if (preg_match('#Edge/([0-9]+\\.)#', $ua, $matches))
|
||||
{
|
||||
$result->browser = 'Edge';
|
||||
$result->version = $matches[1] . '0';
|
||||
return $result;
|
||||
}
|
||||
if (preg_match('#Trident/([0-9]+)\\.[0-9]+#', $ua, $matches))
|
||||
{
|
||||
$result->browser = 'IE';
|
||||
$result->version = ($matches[1] + 4) . '.0';
|
||||
return $result;
|
||||
}
|
||||
if (preg_match('#(MSIE|Chrome|Firefox|Safari)[ /:]([0-9]+\\.[0-9]+)#', $ua, $matches))
|
||||
{
|
||||
$result->browser = $matches[1] === 'MSIE' ? 'IE' : $matches[1];
|
||||
$result->version = $matches[2];
|
||||
return $result;
|
||||
}
|
||||
if (preg_match('#^Opera/.+(?:Opera |Version/)([0-9]+\\.[0-9]+)$#', $ua, $matches))
|
||||
{
|
||||
$result->browser = 'Opera';
|
||||
$result->version = $matches[1];
|
||||
return $result;
|
||||
}
|
||||
if (preg_match('#(?:Konqueror|KHTML)/([0-9]+\\.[0-9]+)$#', $ua, $matches))
|
||||
{
|
||||
$result->browser = 'Konqueror';
|
||||
$result->version = $matches[1];
|
||||
return $result;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue