e_lib 코드들을 composer로 이동
func_http 삭제. guzzle로 대체 php 파일에서 include, require 앞에 있는 구문들을 전부 뒤로 이동.
This commit is contained in:
1 parent
d422c03003
commit
373bcde70b
263 files changed
+22305
-11284
No files matched your search
@@ -1,4 +0,0 @@
|
||||
<?php
|
||||
include(__DIR__.'/plates.php');
|
||||
include(__DIR__.'/meekrodb.2.3.class.php');
|
||||
?>
|
||||
@@ -1,956 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
Copyright (C) 2008-2012 Sergey Tsalkov (stsalkov@gmail.com)
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
class DB {
|
||||
// initial connection
|
||||
public static $dbName = '';
|
||||
public static $user = '';
|
||||
public static $password = '';
|
||||
public static $host = 'localhost';
|
||||
public static $port = null;
|
||||
public static $encoding = 'latin1';
|
||||
|
||||
// configure workings
|
||||
public static $param_char = '%';
|
||||
public static $named_param_seperator = '_';
|
||||
public static $success_handler = false;
|
||||
public static $error_handler = true;
|
||||
public static $throw_exception_on_error = false;
|
||||
public static $nonsql_error_handler = null;
|
||||
public static $throw_exception_on_nonsql_error = false;
|
||||
public static $nested_transactions = false;
|
||||
public static $usenull = true;
|
||||
public static $ssl = array('key' => '', 'cert' => '', 'ca_cert' => '', 'ca_path' => '', 'cipher' => '');
|
||||
public static $connect_options = array(MYSQLI_OPT_CONNECT_TIMEOUT => 30);
|
||||
|
||||
// internal
|
||||
protected static $mdb = null;
|
||||
|
||||
public static function getMDB() {
|
||||
$mdb = DB::$mdb;
|
||||
|
||||
if ($mdb === null) {
|
||||
$mdb = DB::$mdb = new MeekroDB();
|
||||
}
|
||||
|
||||
static $variables_to_sync = array('param_char', 'named_param_seperator', 'success_handler', 'error_handler', 'throw_exception_on_error',
|
||||
'nonsql_error_handler', 'throw_exception_on_nonsql_error', 'nested_transactions', 'usenull', 'ssl', 'connect_options');
|
||||
|
||||
$db_class_vars = get_class_vars('DB'); // the DB::$$var syntax only works in 5.3+
|
||||
|
||||
foreach ($variables_to_sync as $variable) {
|
||||
if ($mdb->$variable !== $db_class_vars[$variable]) {
|
||||
$mdb->$variable = $db_class_vars[$variable];
|
||||
}
|
||||
}
|
||||
|
||||
return $mdb;
|
||||
}
|
||||
|
||||
// yes, this is ugly. __callStatic() only works in 5.3+
|
||||
public static function get() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'get'), $args); }
|
||||
public static function disconnect() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'disconnect'), $args); }
|
||||
public static function query() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'query'), $args); }
|
||||
public static function queryFirstRow() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'queryFirstRow'), $args); }
|
||||
public static function queryOneRow() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'queryOneRow'), $args); }
|
||||
public static function queryAllLists() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'queryAllLists'), $args); }
|
||||
public static function queryFullColumns() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'queryFullColumns'), $args); }
|
||||
public static function queryFirstList() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'queryFirstList'), $args); }
|
||||
public static function queryOneList() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'queryOneList'), $args); }
|
||||
public static function queryFirstColumn() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'queryFirstColumn'), $args); }
|
||||
public static function queryOneColumn() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'queryOneColumn'), $args); }
|
||||
public static function queryFirstField() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'queryFirstField'), $args); }
|
||||
public static function queryOneField() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'queryOneField'), $args); }
|
||||
public static function queryRaw() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'queryRaw'), $args); }
|
||||
public static function queryRawUnbuf() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'queryRawUnbuf'), $args); }
|
||||
|
||||
public static function insert() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'insert'), $args); }
|
||||
public static function insertIgnore() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'insertIgnore'), $args); }
|
||||
public static function insertUpdate() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'insertUpdate'), $args); }
|
||||
public static function replace() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'replace'), $args); }
|
||||
public static function update() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'update'), $args); }
|
||||
public static function delete() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'delete'), $args); }
|
||||
|
||||
public static function insertId() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'insertId'), $args); }
|
||||
public static function count() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'count'), $args); }
|
||||
public static function affectedRows() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'affectedRows'), $args); }
|
||||
|
||||
public static function useDB() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'useDB'), $args); }
|
||||
public static function startTransaction() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'startTransaction'), $args); }
|
||||
public static function commit() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'commit'), $args); }
|
||||
public static function rollback() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'rollback'), $args); }
|
||||
public static function tableList() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'tableList'), $args); }
|
||||
public static function columnList() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'columnList'), $args); }
|
||||
|
||||
public static function sqlEval() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'sqlEval'), $args); }
|
||||
public static function nonSQLError() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'nonSQLError'), $args); }
|
||||
|
||||
public static function serverVersion() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'serverVersion'), $args); }
|
||||
public static function transactionDepth() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'transactionDepth'), $args); }
|
||||
|
||||
|
||||
public static function debugMode($handler = true) {
|
||||
DB::$success_handler = $handler;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
class MeekroDB {
|
||||
// initial connection
|
||||
public $dbName = '';
|
||||
public $user = '';
|
||||
public $password = '';
|
||||
public $host = 'localhost';
|
||||
public $port = null;
|
||||
public $encoding = 'latin1';
|
||||
|
||||
// configure workings
|
||||
public $param_char = '%';
|
||||
public $named_param_seperator = '_';
|
||||
public $success_handler = false;
|
||||
public $error_handler = true;
|
||||
public $throw_exception_on_error = false;
|
||||
public $nonsql_error_handler = null;
|
||||
public $throw_exception_on_nonsql_error = false;
|
||||
public $nested_transactions = false;
|
||||
public $usenull = true;
|
||||
public $ssl = array('key' => '', 'cert' => '', 'ca_cert' => '', 'ca_path' => '', 'cipher' => '');
|
||||
public $connect_options = array(MYSQLI_OPT_CONNECT_TIMEOUT => 30);
|
||||
|
||||
// internal
|
||||
public $internal_mysql = null;
|
||||
public $server_info = null;
|
||||
public $insert_id = 0;
|
||||
public $num_rows = 0;
|
||||
public $affected_rows = 0;
|
||||
public $current_db = null;
|
||||
public $nested_transactions_count = 0;
|
||||
|
||||
|
||||
public function __construct($host=null, $user=null, $password=null, $dbName=null, $port=null, $encoding=null) {
|
||||
if ($host === null) $host = DB::$host;
|
||||
if ($user === null) $user = DB::$user;
|
||||
if ($password === null) $password = DB::$password;
|
||||
if ($dbName === null) $dbName = DB::$dbName;
|
||||
if ($port === null) $port = DB::$port;
|
||||
if ($encoding === null) $encoding = DB::$encoding;
|
||||
|
||||
$this->host = $host;
|
||||
$this->user = $user;
|
||||
$this->password = $password;
|
||||
$this->dbName = $dbName;
|
||||
$this->port = $port;
|
||||
$this->encoding = $encoding;
|
||||
}
|
||||
|
||||
public function get() {
|
||||
$mysql = $this->internal_mysql;
|
||||
|
||||
if (!($mysql instanceof MySQLi)) {
|
||||
if (! $this->port) $this->port = ini_get('mysqli.default_port');
|
||||
$this->current_db = $this->dbName;
|
||||
$mysql = new mysqli();
|
||||
|
||||
$connect_flags = 0;
|
||||
if ($this->ssl['key']) {
|
||||
$mysql->ssl_set($this->ssl['key'], $this->ssl['cert'], $this->ssl['ca_cert'], $this->ssl['ca_path'], $this->ssl['cipher']);
|
||||
$connect_flags |= MYSQLI_CLIENT_SSL;
|
||||
}
|
||||
foreach ($this->connect_options as $key => $value) {
|
||||
$mysql->options($key, $value);
|
||||
}
|
||||
|
||||
// suppress warnings, since we will check connect_error anyway
|
||||
@$mysql->real_connect($this->host, $this->user, $this->password, $this->dbName, $this->port, null, $connect_flags);
|
||||
|
||||
if ($mysql->connect_error) {
|
||||
$this->nonSQLError('Unable to connect to MySQL server! Error: ' . $mysql->connect_error);
|
||||
}
|
||||
|
||||
$mysql->set_charset($this->encoding);
|
||||
$this->internal_mysql = $mysql;
|
||||
$this->server_info = $mysql->server_info;
|
||||
}
|
||||
|
||||
return $mysql;
|
||||
}
|
||||
|
||||
public function disconnect() {
|
||||
$mysqli = $this->internal_mysql;
|
||||
if ($mysqli instanceof MySQLi) {
|
||||
if ($thread_id = $mysqli->thread_id) $mysqli->kill($thread_id);
|
||||
$mysqli->close();
|
||||
}
|
||||
$this->internal_mysql = null;
|
||||
}
|
||||
|
||||
public function nonSQLError($message) {
|
||||
if ($this->throw_exception_on_nonsql_error) {
|
||||
$e = new MeekroDBException($message);
|
||||
throw $e;
|
||||
}
|
||||
|
||||
$error_handler = is_callable($this->nonsql_error_handler) ? $this->nonsql_error_handler : 'meekrodb_error_handler';
|
||||
|
||||
call_user_func($error_handler, array(
|
||||
'type' => 'nonsql',
|
||||
'error' => $message
|
||||
));
|
||||
}
|
||||
|
||||
public function debugMode($handler = true) {
|
||||
$this->success_handler = $handler;
|
||||
}
|
||||
|
||||
public function serverVersion() { $this->get(); return $this->server_info; }
|
||||
public function transactionDepth() { return $this->nested_transactions_count; }
|
||||
public function insertId() { return $this->insert_id; }
|
||||
public function affectedRows() { return $this->affected_rows; }
|
||||
public function count() { $args = func_get_args(); return call_user_func_array(array($this, 'numRows'), $args); }
|
||||
public function numRows() { return $this->num_rows; }
|
||||
|
||||
public function useDB() { $args = func_get_args(); return call_user_func_array(array($this, 'setDB'), $args); }
|
||||
public function setDB($dbName) {
|
||||
$db = $this->get();
|
||||
if (! $db->select_db($dbName)) $this->nonSQLError("Unable to set database to $dbName");
|
||||
$this->current_db = $dbName;
|
||||
}
|
||||
|
||||
|
||||
public function startTransaction() {
|
||||
if ($this->nested_transactions && $this->serverVersion() < '5.5') {
|
||||
return $this->nonSQLError("Nested transactions are only available on MySQL 5.5 and greater. You are using MySQL " . $this->serverVersion());
|
||||
}
|
||||
|
||||
if (!$this->nested_transactions || $this->nested_transactions_count == 0) {
|
||||
$this->query('START TRANSACTION');
|
||||
$this->nested_transactions_count = 1;
|
||||
} else {
|
||||
$this->query("SAVEPOINT LEVEL{$this->nested_transactions_count}");
|
||||
$this->nested_transactions_count++;
|
||||
}
|
||||
|
||||
return $this->nested_transactions_count;
|
||||
}
|
||||
|
||||
public function commit($all=false) {
|
||||
if ($this->nested_transactions && $this->serverVersion() < '5.5') {
|
||||
return $this->nonSQLError("Nested transactions are only available on MySQL 5.5 and greater. You are using MySQL " . $this->serverVersion());
|
||||
}
|
||||
|
||||
if ($this->nested_transactions && $this->nested_transactions_count > 0)
|
||||
$this->nested_transactions_count--;
|
||||
|
||||
if (!$this->nested_transactions || $all || $this->nested_transactions_count == 0) {
|
||||
$this->nested_transactions_count = 0;
|
||||
$this->query('COMMIT');
|
||||
} else {
|
||||
$this->query("RELEASE SAVEPOINT LEVEL{$this->nested_transactions_count}");
|
||||
}
|
||||
|
||||
return $this->nested_transactions_count;
|
||||
}
|
||||
|
||||
public function rollback($all=false) {
|
||||
if ($this->nested_transactions && $this->serverVersion() < '5.5') {
|
||||
return $this->nonSQLError("Nested transactions are only available on MySQL 5.5 and greater. You are using MySQL " . $this->serverVersion());
|
||||
}
|
||||
|
||||
if ($this->nested_transactions && $this->nested_transactions_count > 0)
|
||||
$this->nested_transactions_count--;
|
||||
|
||||
if (!$this->nested_transactions || $all || $this->nested_transactions_count == 0) {
|
||||
$this->nested_transactions_count = 0;
|
||||
$this->query('ROLLBACK');
|
||||
} else {
|
||||
$this->query("ROLLBACK TO SAVEPOINT LEVEL{$this->nested_transactions_count}");
|
||||
}
|
||||
|
||||
return $this->nested_transactions_count;
|
||||
}
|
||||
|
||||
protected function formatTableName($table) {
|
||||
$table = trim($table, '`');
|
||||
|
||||
if (strpos($table, '.')) return implode('.', array_map(array($this, 'formatTableName'), explode('.', $table)));
|
||||
else return '`' . str_replace('`', '``', $table) . '`';
|
||||
}
|
||||
|
||||
public function update() {
|
||||
$args = func_get_args();
|
||||
$table = array_shift($args);
|
||||
$params = array_shift($args);
|
||||
$where = array_shift($args);
|
||||
|
||||
$query = str_replace('%', $this->param_char, "UPDATE %b SET %? WHERE ") . $where;
|
||||
|
||||
array_unshift($args, $params);
|
||||
array_unshift($args, $table);
|
||||
array_unshift($args, $query);
|
||||
return call_user_func_array(array($this, 'query'), $args);
|
||||
}
|
||||
|
||||
public function insertOrReplace($which, $table, $datas, $options=array()) {
|
||||
$datas = unserialize(serialize($datas)); // break references within array
|
||||
$keys = $values = array();
|
||||
|
||||
if (isset($datas[0]) && is_array($datas[0])) {
|
||||
foreach ($datas as $datum) {
|
||||
ksort($datum);
|
||||
if (! $keys) $keys = array_keys($datum);
|
||||
$values[] = array_values($datum);
|
||||
}
|
||||
|
||||
} else {
|
||||
$keys = array_keys($datas);
|
||||
$values = array_values($datas);
|
||||
}
|
||||
|
||||
if (isset($options['ignore']) && $options['ignore']) $which = 'INSERT IGNORE';
|
||||
|
||||
if (isset($options['update']) && is_array($options['update']) && $options['update'] && strtolower($which) == 'insert') {
|
||||
if (array_values($options['update']) !== $options['update']) {
|
||||
return $this->query(
|
||||
str_replace('%', $this->param_char, "INSERT INTO %b %lb VALUES %? ON DUPLICATE KEY UPDATE %?"),
|
||||
$table, $keys, $values, $options['update']);
|
||||
} else {
|
||||
$update_str = array_shift($options['update']);
|
||||
$query_param = array(
|
||||
str_replace('%', $this->param_char, "INSERT INTO %b %lb VALUES %? ON DUPLICATE KEY UPDATE ") . $update_str,
|
||||
$table, $keys, $values);
|
||||
$query_param = array_merge($query_param, $options['update']);
|
||||
return call_user_func_array(array($this, 'query'), $query_param);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $this->query(
|
||||
str_replace('%', $this->param_char, "%l INTO %b %lb VALUES %?"),
|
||||
$which, $table, $keys, $values);
|
||||
}
|
||||
|
||||
public function insert($table, $data) { return $this->insertOrReplace('INSERT', $table, $data); }
|
||||
public function insertIgnore($table, $data) { return $this->insertOrReplace('INSERT', $table, $data, array('ignore' => true)); }
|
||||
public function replace($table, $data) { return $this->insertOrReplace('REPLACE', $table, $data); }
|
||||
|
||||
public function insertUpdate() {
|
||||
$args = func_get_args();
|
||||
$table = array_shift($args);
|
||||
$data = array_shift($args);
|
||||
|
||||
if (! isset($args[0])) { // update will have all the data of the insert
|
||||
if (isset($data[0]) && is_array($data[0])) { //multiple insert rows specified -- failing!
|
||||
$this->nonSQLError("Badly formatted insertUpdate() query -- you didn't specify the update component!");
|
||||
}
|
||||
|
||||
$args[0] = $data;
|
||||
}
|
||||
|
||||
if (is_array($args[0])) $update = $args[0];
|
||||
else $update = $args;
|
||||
|
||||
return $this->insertOrReplace('INSERT', $table, $data, array('update' => $update));
|
||||
}
|
||||
|
||||
public function delete() {
|
||||
$args = func_get_args();
|
||||
$table = $this->formatTableName(array_shift($args));
|
||||
$where = array_shift($args);
|
||||
$buildquery = "DELETE FROM $table WHERE $where";
|
||||
array_unshift($args, $buildquery);
|
||||
return call_user_func_array(array($this, 'query'), $args);
|
||||
}
|
||||
|
||||
public function sqleval() {
|
||||
$args = func_get_args();
|
||||
$text = call_user_func_array(array($this, 'parseQueryParams'), $args);
|
||||
return new MeekroDBEval($text);
|
||||
}
|
||||
|
||||
public function columnList($table) {
|
||||
return $this->queryOneColumn('Field', "SHOW COLUMNS FROM %b", $table);
|
||||
}
|
||||
|
||||
public function tableList($db = null) {
|
||||
if ($db) {
|
||||
$olddb = $this->current_db;
|
||||
$this->useDB($db);
|
||||
}
|
||||
|
||||
$result = $this->queryFirstColumn('SHOW TABLES');
|
||||
if (isset($olddb)) $this->useDB($olddb);
|
||||
return $result;
|
||||
}
|
||||
|
||||
protected function preparseQueryParams() {
|
||||
$args = func_get_args();
|
||||
$sql = trim(strval(array_shift($args)));
|
||||
$args_all = $args;
|
||||
|
||||
if (count($args_all) == 0) return array($sql);
|
||||
|
||||
$param_char_length = strlen($this->param_char);
|
||||
$named_seperator_length = strlen($this->named_param_seperator);
|
||||
|
||||
$types = array(
|
||||
$this->param_char . 'll', // list of literals
|
||||
$this->param_char . 'ls', // list of strings
|
||||
$this->param_char . 'l', // literal
|
||||
$this->param_char . 'li', // list of integers
|
||||
$this->param_char . 'ld', // list of decimals
|
||||
$this->param_char . 'lb', // list of backticks
|
||||
$this->param_char . 'lt', // list of timestamps
|
||||
$this->param_char . 's', // string
|
||||
$this->param_char . 'i', // integer
|
||||
$this->param_char . 'd', // double / decimal
|
||||
$this->param_char . 'b', // backtick
|
||||
$this->param_char . 't', // timestamp
|
||||
$this->param_char . '?', // infer type
|
||||
$this->param_char . 'ss' // search string (like string, surrounded with %'s)
|
||||
);
|
||||
|
||||
// generate list of all MeekroDB variables in our query, and their position
|
||||
// in the form "offset => variable", sorted by offsets
|
||||
$posList = array();
|
||||
foreach ($types as $type) {
|
||||
$lastPos = 0;
|
||||
while (($pos = strpos($sql, $type, $lastPos)) !== false) {
|
||||
$lastPos = $pos + 1;
|
||||
if (isset($posList[$pos]) && strlen($posList[$pos]) > strlen($type)) continue;
|
||||
$posList[$pos] = $type;
|
||||
}
|
||||
}
|
||||
|
||||
ksort($posList);
|
||||
|
||||
// for each MeekroDB variable, substitute it with array(type: i, value: 53) or whatever
|
||||
$chunkyQuery = array(); // preparsed query
|
||||
$pos_adj = 0; // how much we've added or removed from the original sql string
|
||||
foreach ($posList as $pos => $type) {
|
||||
$type = substr($type, $param_char_length); // variable, without % in front of it
|
||||
$length_type = strlen($type) + $param_char_length; // length of variable w/o %
|
||||
|
||||
$new_pos = $pos + $pos_adj; // position of start of variable
|
||||
$new_pos_back = $new_pos + $length_type; // position of end of variable
|
||||
$arg_number_length = 0; // length of any named or numbered parameter addition
|
||||
|
||||
// handle numbered parameters
|
||||
if ($arg_number_length = strspn($sql, '0123456789', $new_pos_back)) {
|
||||
$arg_number = substr($sql, $new_pos_back, $arg_number_length);
|
||||
if (! array_key_exists($arg_number, $args_all)) $this->nonSQLError("Non existent argument reference (arg $arg_number): $sql");
|
||||
|
||||
$arg = $args_all[$arg_number];
|
||||
|
||||
// handle named parameters
|
||||
} else if (substr($sql, $new_pos_back, $named_seperator_length) == $this->named_param_seperator) {
|
||||
$arg_number_length = strspn($sql, 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_',
|
||||
$new_pos_back + $named_seperator_length) + $named_seperator_length;
|
||||
|
||||
$arg_number = substr($sql, $new_pos_back + $named_seperator_length, $arg_number_length - $named_seperator_length);
|
||||
if (count($args_all) != 1 || !is_array($args_all[0])) $this->nonSQLError("If you use named parameters, the second argument must be an array of parameters");
|
||||
if (! array_key_exists($arg_number, $args_all[0])) $this->nonSQLError("Non existent argument reference (arg $arg_number): $sql");
|
||||
|
||||
$arg = $args_all[0][$arg_number];
|
||||
|
||||
} else {
|
||||
$arg_number = 0;
|
||||
$arg = array_shift($args);
|
||||
}
|
||||
|
||||
if ($new_pos > 0) $chunkyQuery[] = substr($sql, 0, $new_pos);
|
||||
|
||||
if (is_object($arg) && ($arg instanceof WhereClause)) {
|
||||
list($clause_sql, $clause_args) = $arg->textAndArgs();
|
||||
array_unshift($clause_args, $clause_sql);
|
||||
$preparsed_sql = call_user_func_array(array($this, 'preparseQueryParams'), $clause_args);
|
||||
$chunkyQuery = array_merge($chunkyQuery, $preparsed_sql);
|
||||
} else {
|
||||
$chunkyQuery[] = array('type' => $type, 'value' => $arg);
|
||||
}
|
||||
|
||||
$sql = substr($sql, $new_pos_back + $arg_number_length);
|
||||
$pos_adj -= $new_pos_back + $arg_number_length;
|
||||
}
|
||||
|
||||
if (strlen($sql) > 0) $chunkyQuery[] = $sql;
|
||||
|
||||
return $chunkyQuery;
|
||||
}
|
||||
|
||||
protected function escape($str) { return "'" . $this->get()->real_escape_string(strval($str)) . "'"; }
|
||||
|
||||
protected function sanitize($value) {
|
||||
if (is_object($value)) {
|
||||
if ($value instanceof MeekroDBEval) return $value->text;
|
||||
else if ($value instanceof DateTime) return $this->escape($value->format('Y-m-d H:i:s'));
|
||||
else return '';
|
||||
}
|
||||
|
||||
if (is_null($value)) return $this->usenull ? 'NULL' : "''";
|
||||
else if (is_bool($value)) return ($value ? 1 : 0);
|
||||
else if (is_int($value)) return $value;
|
||||
else if (is_float($value)) return $value;
|
||||
|
||||
else if (is_array($value)) {
|
||||
// non-assoc array?
|
||||
if (array_values($value) === $value) {
|
||||
if (is_array($value[0])) return implode(', ', array_map(array($this, 'sanitize'), $value));
|
||||
else return '(' . implode(', ', array_map(array($this, 'sanitize'), $value)) . ')';
|
||||
}
|
||||
|
||||
$pairs = array();
|
||||
foreach ($value as $k => $v) {
|
||||
$pairs[] = $this->formatTableName($k) . '=' . $this->sanitize($v);
|
||||
}
|
||||
|
||||
return implode(', ', $pairs);
|
||||
}
|
||||
else return $this->escape($value);
|
||||
}
|
||||
|
||||
protected function parseTS($ts) {
|
||||
if (is_string($ts)) return date('Y-m-d H:i:s', strtotime($ts));
|
||||
else if (is_object($ts) && ($ts instanceof DateTime)) return $ts->format('Y-m-d H:i:s');
|
||||
}
|
||||
|
||||
protected function intval($var) {
|
||||
if (PHP_INT_SIZE == 8) return intval($var);
|
||||
return floor(doubleval($var));
|
||||
}
|
||||
|
||||
protected function parseQueryParams() {
|
||||
$args = func_get_args();
|
||||
$chunkyQuery = call_user_func_array(array($this, 'preparseQueryParams'), $args);
|
||||
|
||||
$query = '';
|
||||
$array_types = array('ls', 'li', 'ld', 'lb', 'll', 'lt');
|
||||
|
||||
foreach ($chunkyQuery as $chunk) {
|
||||
if (is_string($chunk)) {
|
||||
$query .= $chunk;
|
||||
continue;
|
||||
}
|
||||
|
||||
$type = $chunk['type'];
|
||||
$arg = $chunk['value'];
|
||||
$result = '';
|
||||
|
||||
if ($type != '?') {
|
||||
$is_array_type = in_array($type, $array_types, true);
|
||||
if ($is_array_type && !is_array($arg)) $this->nonSQLError("Badly formatted SQL query: Expected array, got scalar instead!");
|
||||
else if (!$is_array_type && is_array($arg)) $this->nonSQLError("Badly formatted SQL query: Expected scalar, got array instead!");
|
||||
}
|
||||
|
||||
if ($type == 's') $result = $this->escape($arg);
|
||||
else if ($type == 'i') $result = $this->intval($arg);
|
||||
else if ($type == 'd') $result = doubleval($arg);
|
||||
else if ($type == 'b') $result = $this->formatTableName($arg);
|
||||
else if ($type == 'l') $result = $arg;
|
||||
else if ($type == 'ss') $result = $this->escape("%" . str_replace(array('%', '_'), array('\%', '\_'), $arg) . "%");
|
||||
else if ($type == 't') $result = $this->escape($this->parseTS($arg));
|
||||
|
||||
else if ($type == 'ls') $result = array_map(array($this, 'escape'), $arg);
|
||||
else if ($type == 'li') $result = array_map(array($this, 'intval'), $arg);
|
||||
else if ($type == 'ld') $result = array_map('doubleval', $arg);
|
||||
else if ($type == 'lb') $result = array_map(array($this, 'formatTableName'), $arg);
|
||||
else if ($type == 'll') $result = $arg;
|
||||
else if ($type == 'lt') $result = array_map(array($this, 'escape'), array_map(array($this, 'parseTS'), $arg));
|
||||
|
||||
else if ($type == '?') $result = $this->sanitize($arg);
|
||||
|
||||
else $this->nonSQLError("Badly formatted SQL query: Invalid MeekroDB param $type");
|
||||
|
||||
if (is_array($result)) $result = '(' . implode(',', $result) . ')';
|
||||
|
||||
$query .= $result;
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
protected function prependCall($function, $args, $prepend) { array_unshift($args, $prepend); return call_user_func_array($function, $args); }
|
||||
public function query() { $args = func_get_args(); return $this->prependCall(array($this, 'queryHelper'), $args, 'assoc'); }
|
||||
public function queryAllLists() { $args = func_get_args(); return $this->prependCall(array($this, 'queryHelper'), $args, 'list'); }
|
||||
public function queryFullColumns() { $args = func_get_args(); return $this->prependCall(array($this, 'queryHelper'), $args, 'full'); }
|
||||
|
||||
public function queryRaw() { $args = func_get_args(); return $this->prependCall(array($this, 'queryHelper'), $args, 'raw_buf'); }
|
||||
public function queryRawUnbuf() { $args = func_get_args(); return $this->prependCall(array($this, 'queryHelper'), $args, 'raw_unbuf'); }
|
||||
|
||||
protected function queryHelper() {
|
||||
$args = func_get_args();
|
||||
$type = array_shift($args);
|
||||
$db = $this->get();
|
||||
|
||||
$is_buffered = true;
|
||||
$row_type = 'assoc'; // assoc, list, raw
|
||||
$full_names = false;
|
||||
|
||||
switch ($type) {
|
||||
case 'assoc':
|
||||
break;
|
||||
case 'list':
|
||||
$row_type = 'list';
|
||||
break;
|
||||
case 'full':
|
||||
$row_type = 'list';
|
||||
$full_names = true;
|
||||
break;
|
||||
case 'raw_buf':
|
||||
$row_type = 'raw';
|
||||
break;
|
||||
case 'raw_unbuf':
|
||||
$is_buffered = false;
|
||||
$row_type = 'raw';
|
||||
break;
|
||||
default:
|
||||
$this->nonSQLError('Error -- invalid argument to queryHelper!');
|
||||
}
|
||||
|
||||
$sql = call_user_func_array(array($this, 'parseQueryParams'), $args);
|
||||
|
||||
if ($this->success_handler) $starttime = microtime(true);
|
||||
$result = $db->query($sql, $is_buffered ? MYSQLI_STORE_RESULT : MYSQLI_USE_RESULT);
|
||||
if ($this->success_handler) $runtime = microtime(true) - $starttime;
|
||||
else $runtime = 0;
|
||||
|
||||
// ----- BEGIN ERROR HANDLING
|
||||
if (!$sql || $db->error) {
|
||||
if ($this->error_handler) {
|
||||
$error_handler = is_callable($this->error_handler) ? $this->error_handler : 'meekrodb_error_handler';
|
||||
|
||||
call_user_func($error_handler, array(
|
||||
'type' => 'sql',
|
||||
'query' => $sql,
|
||||
'error' => $db->error,
|
||||
'code' => $db->errno
|
||||
));
|
||||
}
|
||||
|
||||
if ($this->throw_exception_on_error) {
|
||||
$e = new MeekroDBException($db->error, $sql, $db->errno);
|
||||
throw $e;
|
||||
}
|
||||
} else if ($this->success_handler) {
|
||||
$runtime = sprintf('%f', $runtime * 1000);
|
||||
$success_handler = is_callable($this->success_handler) ? $this->success_handler : 'meekrodb_debugmode_handler';
|
||||
|
||||
call_user_func($success_handler, array(
|
||||
'query' => $sql,
|
||||
'runtime' => $runtime,
|
||||
'affected' => $db->affected_rows
|
||||
));
|
||||
}
|
||||
|
||||
// ----- END ERROR HANDLING
|
||||
|
||||
$this->insert_id = $db->insert_id;
|
||||
$this->affected_rows = $db->affected_rows;
|
||||
|
||||
// mysqli_result->num_rows won't initially show correct results for unbuffered data
|
||||
if ($is_buffered && ($result instanceof MySQLi_Result)) $this->num_rows = $result->num_rows;
|
||||
else $this->num_rows = null;
|
||||
|
||||
if ($row_type == 'raw' || !($result instanceof MySQLi_Result)) return $result;
|
||||
|
||||
$return = array();
|
||||
|
||||
if ($full_names) {
|
||||
$infos = array();
|
||||
foreach ($result->fetch_fields() as $info) {
|
||||
if (strlen($info->table)) $infos[] = $info->table . '.' . $info->name;
|
||||
else $infos[] = $info->name;
|
||||
}
|
||||
}
|
||||
|
||||
while ($row = ($row_type == 'assoc' ? $result->fetch_assoc() : $result->fetch_row())) {
|
||||
if ($full_names) $row = array_combine($infos, $row);
|
||||
$return[] = $row;
|
||||
}
|
||||
|
||||
// free results
|
||||
$result->free();
|
||||
while ($db->more_results()) {
|
||||
$db->next_result();
|
||||
if ($result = $db->use_result()) $result->free();
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
public function queryOneRow() { $args = func_get_args(); return call_user_func_array(array($this, 'queryFirstRow'), $args); }
|
||||
public function queryFirstRow() {
|
||||
$args = func_get_args();
|
||||
$result = call_user_func_array(array($this, 'query'), $args);
|
||||
if (!$result || !is_array($result)) return null;
|
||||
return reset($result);
|
||||
}
|
||||
|
||||
public function queryOneList() { $args = func_get_args(); return call_user_func_array(array($this, 'queryFirstList'), $args); }
|
||||
public function queryFirstList() {
|
||||
$args = func_get_args();
|
||||
$result = call_user_func_array(array($this, 'queryAllLists'), $args);
|
||||
if (!$result || !is_array($result)) return null;
|
||||
return reset($result);
|
||||
}
|
||||
|
||||
public function queryFirstColumn() {
|
||||
$args = func_get_args();
|
||||
$results = call_user_func_array(array($this, 'queryAllLists'), $args);
|
||||
$ret = array();
|
||||
|
||||
if (!count($results) || !count($results[0])) return $ret;
|
||||
|
||||
foreach ($results as $row) {
|
||||
$ret[] = $row[0];
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
public function queryOneColumn() {
|
||||
$args = func_get_args();
|
||||
$column = array_shift($args);
|
||||
$results = call_user_func_array(array($this, 'query'), $args);
|
||||
$ret = array();
|
||||
|
||||
if (!count($results) || !count($results[0])) return $ret;
|
||||
if ($column === null) {
|
||||
$keys = array_keys($results[0]);
|
||||
$column = $keys[0];
|
||||
}
|
||||
|
||||
foreach ($results as $row) {
|
||||
$ret[] = $row[$column];
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
public function queryFirstField() {
|
||||
$args = func_get_args();
|
||||
$row = call_user_func_array(array($this, 'queryFirstList'), $args);
|
||||
if ($row == null) return null;
|
||||
return $row[0];
|
||||
}
|
||||
|
||||
public function queryOneField() {
|
||||
$args = func_get_args();
|
||||
$column = array_shift($args);
|
||||
|
||||
$row = call_user_func_array(array($this, 'queryOneRow'), $args);
|
||||
if ($row == null) {
|
||||
return null;
|
||||
} else if ($column === null) {
|
||||
$keys = array_keys($row);
|
||||
$column = $keys[0];
|
||||
}
|
||||
|
||||
return $row[$column];
|
||||
}
|
||||
}
|
||||
|
||||
class WhereClause {
|
||||
public $type = 'and'; //AND or OR
|
||||
public $negate = false;
|
||||
public $clauses = array();
|
||||
|
||||
function __construct($type) {
|
||||
$type = strtolower($type);
|
||||
if ($type !== 'or' && $type !== 'and') DB::nonSQLError('you must use either WhereClause(and) or WhereClause(or)');
|
||||
$this->type = $type;
|
||||
}
|
||||
|
||||
function add() {
|
||||
$args = func_get_args();
|
||||
$sql = array_shift($args);
|
||||
|
||||
if ($sql instanceof WhereClause) {
|
||||
$this->clauses[] = $sql;
|
||||
} else {
|
||||
$this->clauses[] = array('sql' => $sql, 'args' => $args);
|
||||
}
|
||||
}
|
||||
|
||||
function negateLast() {
|
||||
$i = count($this->clauses) - 1;
|
||||
if (!isset($this->clauses[$i])) return;
|
||||
|
||||
if ($this->clauses[$i] instanceof WhereClause) {
|
||||
$this->clauses[$i]->negate();
|
||||
} else {
|
||||
$this->clauses[$i]['sql'] = 'NOT (' . $this->clauses[$i]['sql'] . ')';
|
||||
}
|
||||
}
|
||||
|
||||
function negate() {
|
||||
$this->negate = ! $this->negate;
|
||||
}
|
||||
|
||||
function addClause($type) {
|
||||
$r = new WhereClause($type);
|
||||
$this->add($r);
|
||||
return $r;
|
||||
}
|
||||
|
||||
function count() {
|
||||
return count($this->clauses);
|
||||
}
|
||||
|
||||
function textAndArgs() {
|
||||
$sql = array();
|
||||
$args = array();
|
||||
|
||||
if (count($this->clauses) == 0) return array('(1)', $args);
|
||||
|
||||
foreach ($this->clauses as $clause) {
|
||||
if ($clause instanceof WhereClause) {
|
||||
list($clause_sql, $clause_args) = $clause->textAndArgs();
|
||||
} else {
|
||||
$clause_sql = $clause['sql'];
|
||||
$clause_args = $clause['args'];
|
||||
}
|
||||
|
||||
$sql[] = "($clause_sql)";
|
||||
$args = array_merge($args, $clause_args);
|
||||
}
|
||||
|
||||
if ($this->type == 'and') $sql = implode(' AND ', $sql);
|
||||
else $sql = implode(' OR ', $sql);
|
||||
|
||||
if ($this->negate) $sql = '(NOT ' . $sql . ')';
|
||||
return array($sql, $args);
|
||||
}
|
||||
|
||||
// backwards compatability
|
||||
// we now return full WhereClause object here and evaluate it in preparseQueryParams
|
||||
function text() { return $this; }
|
||||
}
|
||||
|
||||
class DBTransaction {
|
||||
private $committed = false;
|
||||
|
||||
function __construct() {
|
||||
DB::startTransaction();
|
||||
}
|
||||
function __destruct() {
|
||||
if (! $this->committed) DB::rollback();
|
||||
}
|
||||
function commit() {
|
||||
DB::commit();
|
||||
$this->committed = true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
class MeekroDBException extends Exception {
|
||||
protected $query = '';
|
||||
|
||||
function __construct($message='', $query='', $code = 0) {
|
||||
parent::__construct($message);
|
||||
$this->query = $query;
|
||||
$this->code = $code;
|
||||
}
|
||||
|
||||
public function getQuery() { return $this->query; }
|
||||
}
|
||||
|
||||
class DBHelper {
|
||||
/*
|
||||
verticalSlice
|
||||
1. For an array of assoc rays, return an array of values for a particular key
|
||||
2. if $keyfield is given, same as above but use that hash key as the key in new array
|
||||
*/
|
||||
|
||||
public static function verticalSlice($array, $field, $keyfield = null) {
|
||||
$array = (array) $array;
|
||||
|
||||
$R = array();
|
||||
foreach ($array as $obj) {
|
||||
if (! array_key_exists($field, $obj)) die("verticalSlice: array doesn't have requested field\n");
|
||||
|
||||
if ($keyfield) {
|
||||
if (! array_key_exists($keyfield, $obj)) die("verticalSlice: array doesn't have requested field\n");
|
||||
$R[$obj[$keyfield]] = $obj[$field];
|
||||
} else {
|
||||
$R[] = $obj[$field];
|
||||
}
|
||||
}
|
||||
return $R;
|
||||
}
|
||||
|
||||
/*
|
||||
reIndex
|
||||
For an array of assoc rays, return a new array of assoc rays using a certain field for keys
|
||||
*/
|
||||
|
||||
public static function reIndex() {
|
||||
$fields = func_get_args();
|
||||
$array = array_shift($fields);
|
||||
$array = (array) $array;
|
||||
|
||||
$R = array();
|
||||
foreach ($array as $obj) {
|
||||
$target =& $R;
|
||||
|
||||
foreach ($fields as $field) {
|
||||
if (! array_key_exists($field, $obj)) die("reIndex: array doesn't have requested field\n");
|
||||
|
||||
$nextkey = $obj[$field];
|
||||
$target =& $target[$nextkey];
|
||||
}
|
||||
$target = $obj;
|
||||
}
|
||||
return $R;
|
||||
}
|
||||
}
|
||||
|
||||
function meekrodb_error_handler($params) {
|
||||
if (isset($params['query'])) $out[] = "QUERY: " . $params['query'];
|
||||
if (isset($params['error'])) $out[] = "ERROR: " . $params['error'];
|
||||
$out[] = "";
|
||||
|
||||
if (php_sapi_name() == 'cli' && empty($_SERVER['REMOTE_ADDR'])) {
|
||||
echo implode("\n", $out);
|
||||
} else {
|
||||
echo implode("<br>\n", $out);
|
||||
}
|
||||
|
||||
die;
|
||||
}
|
||||
|
||||
function meekrodb_debugmode_handler($params) {
|
||||
echo "QUERY: " . $params['query'] . " [" . $params['runtime'] . " ms]";
|
||||
if (php_sapi_name() == 'cli' && empty($_SERVER['REMOTE_ADDR'])) {
|
||||
echo "\n";
|
||||
} else {
|
||||
echo "<br>\n";
|
||||
}
|
||||
}
|
||||
|
||||
class MeekroDBEval {
|
||||
public $text = '';
|
||||
|
||||
function __construct($text) {
|
||||
$this->text = $text;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,504 +0,0 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the Lesser GPL. It also counts
|
||||
as the successor of the GNU Library Public License, version 2, hence
|
||||
the version number 2.1.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Lesser General Public License, applies to some
|
||||
specially designated software packages--typically libraries--of the
|
||||
Free Software Foundation and other authors who decide to use it. You
|
||||
can use it too, but we suggest you first think carefully about whether
|
||||
this license or the ordinary General Public License is the better
|
||||
strategy to use in any particular case, based on the explanations below.
|
||||
|
||||
When we speak of free software, we are referring to freedom of use,
|
||||
not price. Our General Public Licenses are designed to make sure that
|
||||
you have the freedom to distribute copies of free software (and charge
|
||||
for this service if you wish); that you receive source code or can get
|
||||
it if you want it; that you can change the software and use pieces of
|
||||
it in new free programs; and that you are informed that you can do
|
||||
these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
distributors to deny you these rights or to ask you to surrender these
|
||||
rights. These restrictions translate to certain responsibilities for
|
||||
you if you distribute copies of the library or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link other code with the library, you must provide
|
||||
complete object files to the recipients, so that they can relink them
|
||||
with the library after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
We protect your rights with a two-step method: (1) we copyright the
|
||||
library, and (2) we offer you this license, which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
To protect each distributor, we want to make it very clear that
|
||||
there is no warranty for the free library. Also, if the library is
|
||||
modified by someone else and passed on, the recipients should know
|
||||
that what they have is not the original version, so that the original
|
||||
author's reputation will not be affected by problems that might be
|
||||
introduced by others.
|
||||
|
||||
Finally, software patents pose a constant threat to the existence of
|
||||
any free program. We wish to make sure that a company cannot
|
||||
effectively restrict the users of a free program by obtaining a
|
||||
restrictive license from a patent holder. Therefore, we insist that
|
||||
any patent license obtained for a version of the library must be
|
||||
consistent with the full freedom of use specified in this license.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the
|
||||
ordinary GNU General Public License. This license, the GNU Lesser
|
||||
General Public License, applies to certain designated libraries, and
|
||||
is quite different from the ordinary General Public License. We use
|
||||
this license for certain libraries in order to permit linking those
|
||||
libraries into non-free programs.
|
||||
|
||||
When a program is linked with a library, whether statically or using
|
||||
a shared library, the combination of the two is legally speaking a
|
||||
combined work, a derivative of the original library. The ordinary
|
||||
General Public License therefore permits such linking only if the
|
||||
entire combination fits its criteria of freedom. The Lesser General
|
||||
Public License permits more lax criteria for linking other code with
|
||||
the library.
|
||||
|
||||
We call this license the "Lesser" General Public License because it
|
||||
does Less to protect the user's freedom than the ordinary General
|
||||
Public License. It also provides other free software developers Less
|
||||
of an advantage over competing non-free programs. These disadvantages
|
||||
are the reason we use the ordinary General Public License for many
|
||||
libraries. However, the Lesser license provides advantages in certain
|
||||
special circumstances.
|
||||
|
||||
For example, on rare occasions, there may be a special need to
|
||||
encourage the widest possible use of a certain library, so that it becomes
|
||||
a de-facto standard. To achieve this, non-free programs must be
|
||||
allowed to use the library. A more frequent case is that a free
|
||||
library does the same job as widely used non-free libraries. In this
|
||||
case, there is little to gain by limiting the free library to free
|
||||
software only, so we use the Lesser General Public License.
|
||||
|
||||
In other cases, permission to use a particular library in non-free
|
||||
programs enables a greater number of people to use a large body of
|
||||
free software. For example, permission to use the GNU C Library in
|
||||
non-free programs enables many more people to use the whole GNU
|
||||
operating system, as well as its variant, the GNU/Linux operating
|
||||
system.
|
||||
|
||||
Although the Lesser General Public License is Less protective of the
|
||||
users' freedom, it does ensure that the user of a program that is
|
||||
linked with the Library has the freedom and the wherewithal to run
|
||||
that program using a modified version of the Library.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, whereas the latter must
|
||||
be combined with the library in order to run.
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library or other
|
||||
program which contains a notice placed by the copyright holder or
|
||||
other authorized party saying it may be distributed under the terms of
|
||||
this Lesser General Public License (also called "this License").
|
||||
Each licensee is addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control compilation
|
||||
and installation of the library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided that
|
||||
you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||
all the notices that refer to this License and to the absence of any
|
||||
warranty; and distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy,
|
||||
and you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
2. You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Library, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you accompany
|
||||
it with the complete corresponding machine-readable source code, which
|
||||
must be distributed under the terms of Sections 1 and 2 above on a
|
||||
medium customarily used for software interchange.
|
||||
|
||||
If distribution of object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also combine or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (1) uses at run time a
|
||||
copy of the library already present on the user's computer system,
|
||||
rather than copying library functions into the executable, and (2)
|
||||
will operate properly with a modified version of the library, if
|
||||
the user installs one, as long as the modified version is
|
||||
interface-compatible with the version that the work was made with.
|
||||
|
||||
c) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
d) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
e) verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the materials to be distributed need not include anything that is
|
||||
normally distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate your
|
||||
rights under this License. However, parties who have received copies,
|
||||
or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
|
||||
9. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties with
|
||||
this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Library.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any
|
||||
particular circumstance, the balance of the section is intended to apply,
|
||||
and the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library under this License may add
|
||||
an explicit geographical distribution limitation excluding those countries,
|
||||
so that distribution is permitted only in or among countries not thus
|
||||
excluded. In such case, this License incorporates the limitation as if
|
||||
written in the body of this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Lesser General Public License from time to time.
|
||||
Such new versions will be similar in spirit to the present version,
|
||||
but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Library
|
||||
specifies a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
write to the author to ask for permission. For software which is
|
||||
copyrighted by the Free Software Foundation, write to the Free
|
||||
Software Foundation; we sometimes make exceptions for this. Our
|
||||
decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Libraries
|
||||
|
||||
If you develop a new library, and you want it to be of the greatest
|
||||
possible use to the public, we recommend making it free software that
|
||||
everyone can redistribute and change. You can do so by permitting
|
||||
redistribution under these terms (or, alternatively, under the terms of the
|
||||
ordinary General Public License).
|
||||
|
||||
To apply these terms, attach the following notices to the library. It is
|
||||
safest to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least the
|
||||
"copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the library's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
||||
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* PHPMailer SPL autoloader.
|
||||
* PHP Version 5
|
||||
* @package PHPMailer
|
||||
* @link https://github.com/PHPMailer/PHPMailer/ The PHPMailer GitHub project
|
||||
* @author Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk>
|
||||
* @author Jim Jagielski (jimjag) <jimjag@gmail.com>
|
||||
* @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net>
|
||||
* @author Brent R. Matzelle (original founder)
|
||||
* @copyright 2012 - 2014 Marcus Bointon
|
||||
* @copyright 2010 - 2012 Jim Jagielski
|
||||
* @copyright 2004 - 2009 Andy Prevost
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
* @note This program is distributed in the hope that it will be useful - WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* PHPMailer SPL autoloader.
|
||||
* @param string $classname The name of the class to load
|
||||
*/
|
||||
function PHPMailerAutoload($classname)
|
||||
{
|
||||
//Can't use __DIR__ as it's only in PHP 5.3+
|
||||
$filename = dirname(__FILE__).DIRECTORY_SEPARATOR.'class.'.strtolower($classname).'.php';
|
||||
if (is_readable($filename)) {
|
||||
require $filename;
|
||||
}
|
||||
}
|
||||
|
||||
if (version_compare(PHP_VERSION, '5.1.2', '>=')) {
|
||||
//SPL autoloading was introduced in PHP 5.1.2
|
||||
if (version_compare(PHP_VERSION, '5.3.0', '>=')) {
|
||||
spl_autoload_register('PHPMailerAutoload', true, true);
|
||||
} else {
|
||||
spl_autoload_register('PHPMailerAutoload');
|
||||
}
|
||||
} else {
|
||||
/**
|
||||
* Fall back to traditional autoload for old PHP versions
|
||||
* @param string $classname The name of the class to load
|
||||
*/
|
||||
function __autoload($classname)
|
||||
{
|
||||
PHPMailerAutoload($classname);
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
5.2.26
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,197 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* PHPMailer - PHP email creation and transport class.
|
||||
* PHP Version 5.4
|
||||
* @package PHPMailer
|
||||
* @link https://github.com/PHPMailer/PHPMailer/ The PHPMailer GitHub project
|
||||
* @author Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk>
|
||||
* @author Jim Jagielski (jimjag) <jimjag@gmail.com>
|
||||
* @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net>
|
||||
* @author Brent R. Matzelle (original founder)
|
||||
* @copyright 2012 - 2014 Marcus Bointon
|
||||
* @copyright 2010 - 2012 Jim Jagielski
|
||||
* @copyright 2004 - 2009 Andy Prevost
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
* @note This program is distributed in the hope that it will be useful - WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* PHPMailerOAuth - PHPMailer subclass adding OAuth support.
|
||||
* @package PHPMailer
|
||||
* @author @sherryl4george
|
||||
* @author Marcus Bointon (@Synchro) <phpmailer@synchromedia.co.uk>
|
||||
*/
|
||||
class PHPMailerOAuth extends PHPMailer
|
||||
{
|
||||
/**
|
||||
* The OAuth user's email address
|
||||
* @var string
|
||||
*/
|
||||
public $oauthUserEmail = '';
|
||||
|
||||
/**
|
||||
* The OAuth refresh token
|
||||
* @var string
|
||||
*/
|
||||
public $oauthRefreshToken = '';
|
||||
|
||||
/**
|
||||
* The OAuth client ID
|
||||
* @var string
|
||||
*/
|
||||
public $oauthClientId = '';
|
||||
|
||||
/**
|
||||
* The OAuth client secret
|
||||
* @var string
|
||||
*/
|
||||
public $oauthClientSecret = '';
|
||||
|
||||
/**
|
||||
* An instance of the PHPMailerOAuthGoogle class.
|
||||
* @var PHPMailerOAuthGoogle
|
||||
* @access protected
|
||||
*/
|
||||
protected $oauth = null;
|
||||
|
||||
/**
|
||||
* Get a PHPMailerOAuthGoogle instance to use.
|
||||
* @return PHPMailerOAuthGoogle
|
||||
*/
|
||||
public function getOAUTHInstance()
|
||||
{
|
||||
if (!is_object($this->oauth)) {
|
||||
$this->oauth = new PHPMailerOAuthGoogle(
|
||||
$this->oauthUserEmail,
|
||||
$this->oauthClientSecret,
|
||||
$this->oauthClientId,
|
||||
$this->oauthRefreshToken
|
||||
);
|
||||
}
|
||||
return $this->oauth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiate a connection to an SMTP server.
|
||||
* Overrides the original smtpConnect method to add support for OAuth.
|
||||
* @param array $options An array of options compatible with stream_context_create()
|
||||
* @uses SMTP
|
||||
* @access public
|
||||
* @return bool
|
||||
* @throws phpmailerException
|
||||
*/
|
||||
public function smtpConnect($options = array())
|
||||
{
|
||||
if (is_null($this->smtp)) {
|
||||
$this->smtp = $this->getSMTPInstance();
|
||||
}
|
||||
|
||||
if (is_null($this->oauth)) {
|
||||
$this->oauth = $this->getOAUTHInstance();
|
||||
}
|
||||
|
||||
// Already connected?
|
||||
if ($this->smtp->connected()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->smtp->setTimeout($this->Timeout);
|
||||
$this->smtp->setDebugLevel($this->SMTPDebug);
|
||||
$this->smtp->setDebugOutput($this->Debugoutput);
|
||||
$this->smtp->setVerp($this->do_verp);
|
||||
$hosts = explode(';', $this->Host);
|
||||
$lastexception = null;
|
||||
|
||||
foreach ($hosts as $hostentry) {
|
||||
$hostinfo = array();
|
||||
if (!preg_match('/^((ssl|tls):\/\/)*([a-zA-Z0-9\.-]*):?([0-9]*)$/', trim($hostentry), $hostinfo)) {
|
||||
// Not a valid host entry
|
||||
continue;
|
||||
}
|
||||
// $hostinfo[2]: optional ssl or tls prefix
|
||||
// $hostinfo[3]: the hostname
|
||||
// $hostinfo[4]: optional port number
|
||||
// The host string prefix can temporarily override the current setting for SMTPSecure
|
||||
// If it's not specified, the default value is used
|
||||
$prefix = '';
|
||||
$secure = $this->SMTPSecure;
|
||||
$tls = ($this->SMTPSecure == 'tls');
|
||||
if ('ssl' == $hostinfo[2] or ('' == $hostinfo[2] and 'ssl' == $this->SMTPSecure)) {
|
||||
$prefix = 'ssl://';
|
||||
$tls = false; // Can't have SSL and TLS at the same time
|
||||
$secure = 'ssl';
|
||||
} elseif ($hostinfo[2] == 'tls') {
|
||||
$tls = true;
|
||||
// tls doesn't use a prefix
|
||||
$secure = 'tls';
|
||||
}
|
||||
//Do we need the OpenSSL extension?
|
||||
$sslext = defined('OPENSSL_ALGO_SHA1');
|
||||
if ('tls' === $secure or 'ssl' === $secure) {
|
||||
//Check for an OpenSSL constant rather than using extension_loaded, which is sometimes disabled
|
||||
if (!$sslext) {
|
||||
throw new phpmailerException($this->lang('extension_missing').'openssl', self::STOP_CRITICAL);
|
||||
}
|
||||
}
|
||||
$host = $hostinfo[3];
|
||||
$port = $this->Port;
|
||||
$tport = (integer)$hostinfo[4];
|
||||
if ($tport > 0 and $tport < 65536) {
|
||||
$port = $tport;
|
||||
}
|
||||
if ($this->smtp->connect($prefix . $host, $port, $this->Timeout, $options)) {
|
||||
try {
|
||||
if ($this->Helo) {
|
||||
$hello = $this->Helo;
|
||||
} else {
|
||||
$hello = $this->serverHostname();
|
||||
}
|
||||
$this->smtp->hello($hello);
|
||||
//Automatically enable TLS encryption if:
|
||||
// * it's not disabled
|
||||
// * we have openssl extension
|
||||
// * we are not already using SSL
|
||||
// * the server offers STARTTLS
|
||||
if ($this->SMTPAutoTLS and $sslext and $secure != 'ssl' and $this->smtp->getServerExt('STARTTLS')) {
|
||||
$tls = true;
|
||||
}
|
||||
if ($tls) {
|
||||
if (!$this->smtp->startTLS()) {
|
||||
throw new phpmailerException($this->lang('connect_host'));
|
||||
}
|
||||
// We must resend HELO after tls negotiation
|
||||
$this->smtp->hello($hello);
|
||||
}
|
||||
if ($this->SMTPAuth) {
|
||||
if (!$this->smtp->authenticate(
|
||||
$this->Username,
|
||||
$this->Password,
|
||||
$this->AuthType,
|
||||
$this->Realm,
|
||||
$this->Workstation,
|
||||
$this->oauth
|
||||
)
|
||||
) {
|
||||
throw new phpmailerException($this->lang('authenticate'));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} catch (phpmailerException $exc) {
|
||||
$lastexception = $exc;
|
||||
$this->edebug($exc->getMessage());
|
||||
// We must have connected, but then failed TLS or Auth, so close connection nicely
|
||||
$this->smtp->quit();
|
||||
}
|
||||
}
|
||||
}
|
||||
// If we get here, all connection attempts have failed, so close connection hard
|
||||
$this->smtp->close();
|
||||
// As we've caught all exceptions, just report whatever the last one was
|
||||
if ($this->exceptions and !is_null($lastexception)) {
|
||||
throw $lastexception;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* PHPMailer - PHP email creation and transport class.
|
||||
* PHP Version 5.4
|
||||
* @package PHPMailer
|
||||
* @link https://github.com/PHPMailer/PHPMailer/ The PHPMailer GitHub project
|
||||
* @author Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk>
|
||||
* @author Jim Jagielski (jimjag) <jimjag@gmail.com>
|
||||
* @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net>
|
||||
* @author Brent R. Matzelle (original founder)
|
||||
* @copyright 2012 - 2014 Marcus Bointon
|
||||
* @copyright 2010 - 2012 Jim Jagielski
|
||||
* @copyright 2004 - 2009 Andy Prevost
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
* @note This program is distributed in the hope that it will be useful - WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* PHPMailerOAuthGoogle - Wrapper for League OAuth2 Google provider.
|
||||
* @package PHPMailer
|
||||
* @author @sherryl4george
|
||||
* @author Marcus Bointon (@Synchro) <phpmailer@synchromedia.co.uk>
|
||||
* @link https://github.com/thephpleague/oauth2-client
|
||||
*/
|
||||
class PHPMailerOAuthGoogle
|
||||
{
|
||||
private $oauthUserEmail = '';
|
||||
private $oauthRefreshToken = '';
|
||||
private $oauthClientId = '';
|
||||
private $oauthClientSecret = '';
|
||||
|
||||
/**
|
||||
* @param string $UserEmail
|
||||
* @param string $ClientSecret
|
||||
* @param string $ClientId
|
||||
* @param string $RefreshToken
|
||||
*/
|
||||
public function __construct(
|
||||
$UserEmail,
|
||||
$ClientSecret,
|
||||
$ClientId,
|
||||
$RefreshToken
|
||||
) {
|
||||
$this->oauthClientId = $ClientId;
|
||||
$this->oauthClientSecret = $ClientSecret;
|
||||
$this->oauthRefreshToken = $RefreshToken;
|
||||
$this->oauthUserEmail = $UserEmail;
|
||||
}
|
||||
|
||||
private function getProvider()
|
||||
{
|
||||
return new League\OAuth2\Client\Provider\Google([
|
||||
'clientId' => $this->oauthClientId,
|
||||
'clientSecret' => $this->oauthClientSecret
|
||||
]);
|
||||
}
|
||||
|
||||
private function getGrant()
|
||||
{
|
||||
return new \League\OAuth2\Client\Grant\RefreshToken();
|
||||
}
|
||||
|
||||
private function getToken()
|
||||
{
|
||||
$provider = $this->getProvider();
|
||||
$grant = $this->getGrant();
|
||||
return $provider->getAccessToken($grant, ['refresh_token' => $this->oauthRefreshToken]);
|
||||
}
|
||||
|
||||
public function getOauth64()
|
||||
{
|
||||
$token = $this->getToken();
|
||||
return base64_encode("user=" . $this->oauthUserEmail . "\001auth=Bearer " . $token . "\001\001");
|
||||
}
|
||||
}
|
||||
@@ -1,407 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* PHPMailer POP-Before-SMTP Authentication Class.
|
||||
* PHP Version 5
|
||||
* @package PHPMailer
|
||||
* @link https://github.com/PHPMailer/PHPMailer/
|
||||
* @author Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk>
|
||||
* @author Jim Jagielski (jimjag) <jimjag@gmail.com>
|
||||
* @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net>
|
||||
* @author Brent R. Matzelle (original founder)
|
||||
* @copyright 2012 - 2014 Marcus Bointon
|
||||
* @copyright 2010 - 2012 Jim Jagielski
|
||||
* @copyright 2004 - 2009 Andy Prevost
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
* @note This program is distributed in the hope that it will be useful - WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* PHPMailer POP-Before-SMTP Authentication Class.
|
||||
* Specifically for PHPMailer to use for RFC1939 POP-before-SMTP authentication.
|
||||
* Does not support APOP.
|
||||
* @package PHPMailer
|
||||
* @author Richard Davey (original author) <rich@corephp.co.uk>
|
||||
* @author Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk>
|
||||
* @author Jim Jagielski (jimjag) <jimjag@gmail.com>
|
||||
* @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net>
|
||||
*/
|
||||
class POP3
|
||||
{
|
||||
/**
|
||||
* The POP3 PHPMailer Version number.
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
public $Version = '5.2.26';
|
||||
|
||||
/**
|
||||
* Default POP3 port number.
|
||||
* @var integer
|
||||
* @access public
|
||||
*/
|
||||
public $POP3_PORT = 110;
|
||||
|
||||
/**
|
||||
* Default timeout in seconds.
|
||||
* @var integer
|
||||
* @access public
|
||||
*/
|
||||
public $POP3_TIMEOUT = 30;
|
||||
|
||||
/**
|
||||
* POP3 Carriage Return + Line Feed.
|
||||
* @var string
|
||||
* @access public
|
||||
* @deprecated Use the constant instead
|
||||
*/
|
||||
public $CRLF = "\r\n";
|
||||
|
||||
/**
|
||||
* Debug display level.
|
||||
* Options: 0 = no, 1+ = yes
|
||||
* @var integer
|
||||
* @access public
|
||||
*/
|
||||
public $do_debug = 0;
|
||||
|
||||
/**
|
||||
* POP3 mail server hostname.
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
public $host;
|
||||
|
||||
/**
|
||||
* POP3 port number.
|
||||
* @var integer
|
||||
* @access public
|
||||
*/
|
||||
public $port;
|
||||
|
||||
/**
|
||||
* POP3 Timeout Value in seconds.
|
||||
* @var integer
|
||||
* @access public
|
||||
*/
|
||||
public $tval;
|
||||
|
||||
/**
|
||||
* POP3 username
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
public $username;
|
||||
|
||||
/**
|
||||
* POP3 password.
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
public $password;
|
||||
|
||||
/**
|
||||
* Resource handle for the POP3 connection socket.
|
||||
* @var resource
|
||||
* @access protected
|
||||
*/
|
||||
protected $pop_conn;
|
||||
|
||||
/**
|
||||
* Are we connected?
|
||||
* @var boolean
|
||||
* @access protected
|
||||
*/
|
||||
protected $connected = false;
|
||||
|
||||
/**
|
||||
* Error container.
|
||||
* @var array
|
||||
* @access protected
|
||||
*/
|
||||
protected $errors = array();
|
||||
|
||||
/**
|
||||
* Line break constant
|
||||
*/
|
||||
const CRLF = "\r\n";
|
||||
|
||||
/**
|
||||
* Simple static wrapper for all-in-one POP before SMTP
|
||||
* @param $host
|
||||
* @param integer|boolean $port The port number to connect to
|
||||
* @param integer|boolean $timeout The timeout value
|
||||
* @param string $username
|
||||
* @param string $password
|
||||
* @param integer $debug_level
|
||||
* @return boolean
|
||||
*/
|
||||
public static function popBeforeSmtp(
|
||||
$host,
|
||||
$port = false,
|
||||
$timeout = false,
|
||||
$username = '',
|
||||
$password = '',
|
||||
$debug_level = 0
|
||||
) {
|
||||
$pop = new POP3;
|
||||
return $pop->authorise($host, $port, $timeout, $username, $password, $debug_level);
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate with a POP3 server.
|
||||
* A connect, login, disconnect sequence
|
||||
* appropriate for POP-before SMTP authorisation.
|
||||
* @access public
|
||||
* @param string $host The hostname to connect to
|
||||
* @param integer|boolean $port The port number to connect to
|
||||
* @param integer|boolean $timeout The timeout value
|
||||
* @param string $username
|
||||
* @param string $password
|
||||
* @param integer $debug_level
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorise($host, $port = false, $timeout = false, $username = '', $password = '', $debug_level = 0)
|
||||
{
|
||||
$this->host = $host;
|
||||
// If no port value provided, use default
|
||||
if (false === $port) {
|
||||
$this->port = $this->POP3_PORT;
|
||||
} else {
|
||||
$this->port = (integer)$port;
|
||||
}
|
||||
// If no timeout value provided, use default
|
||||
if (false === $timeout) {
|
||||
$this->tval = $this->POP3_TIMEOUT;
|
||||
} else {
|
||||
$this->tval = (integer)$timeout;
|
||||
}
|
||||
$this->do_debug = $debug_level;
|
||||
$this->username = $username;
|
||||
$this->password = $password;
|
||||
// Reset the error log
|
||||
$this->errors = array();
|
||||
// connect
|
||||
$result = $this->connect($this->host, $this->port, $this->tval);
|
||||
if ($result) {
|
||||
$login_result = $this->login($this->username, $this->password);
|
||||
if ($login_result) {
|
||||
$this->disconnect();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// We need to disconnect regardless of whether the login succeeded
|
||||
$this->disconnect();
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect to a POP3 server.
|
||||
* @access public
|
||||
* @param string $host
|
||||
* @param integer|boolean $port
|
||||
* @param integer $tval
|
||||
* @return boolean
|
||||
*/
|
||||
public function connect($host, $port = false, $tval = 30)
|
||||
{
|
||||
// Are we already connected?
|
||||
if ($this->connected) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//On Windows this will raise a PHP Warning error if the hostname doesn't exist.
|
||||
//Rather than suppress it with @fsockopen, capture it cleanly instead
|
||||
set_error_handler(array($this, 'catchWarning'));
|
||||
|
||||
if (false === $port) {
|
||||
$port = $this->POP3_PORT;
|
||||
}
|
||||
|
||||
// connect to the POP3 server
|
||||
$this->pop_conn = fsockopen(
|
||||
$host, // POP3 Host
|
||||
$port, // Port #
|
||||
$errno, // Error Number
|
||||
$errstr, // Error Message
|
||||
$tval
|
||||
); // Timeout (seconds)
|
||||
// Restore the error handler
|
||||
restore_error_handler();
|
||||
|
||||
// Did we connect?
|
||||
if (false === $this->pop_conn) {
|
||||
// It would appear not...
|
||||
$this->setError(array(
|
||||
'error' => "Failed to connect to server $host on port $port",
|
||||
'errno' => $errno,
|
||||
'errstr' => $errstr
|
||||
));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Increase the stream time-out
|
||||
stream_set_timeout($this->pop_conn, $tval, 0);
|
||||
|
||||
// Get the POP3 server response
|
||||
$pop3_response = $this->getResponse();
|
||||
// Check for the +OK
|
||||
if ($this->checkResponse($pop3_response)) {
|
||||
// The connection is established and the POP3 server is talking
|
||||
$this->connected = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Log in to the POP3 server.
|
||||
* Does not support APOP (RFC 2828, 4949).
|
||||
* @access public
|
||||
* @param string $username
|
||||
* @param string $password
|
||||
* @return boolean
|
||||
*/
|
||||
public function login($username = '', $password = '')
|
||||
{
|
||||
if (!$this->connected) {
|
||||
$this->setError('Not connected to POP3 server');
|
||||
}
|
||||
if (empty($username)) {
|
||||
$username = $this->username;
|
||||
}
|
||||
if (empty($password)) {
|
||||
$password = $this->password;
|
||||
}
|
||||
|
||||
// Send the Username
|
||||
$this->sendString("USER $username" . self::CRLF);
|
||||
$pop3_response = $this->getResponse();
|
||||
if ($this->checkResponse($pop3_response)) {
|
||||
// Send the Password
|
||||
$this->sendString("PASS $password" . self::CRLF);
|
||||
$pop3_response = $this->getResponse();
|
||||
if ($this->checkResponse($pop3_response)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect from the POP3 server.
|
||||
* @access public
|
||||
*/
|
||||
public function disconnect()
|
||||
{
|
||||
$this->sendString('QUIT');
|
||||
//The QUIT command may cause the daemon to exit, which will kill our connection
|
||||
//So ignore errors here
|
||||
try {
|
||||
@fclose($this->pop_conn);
|
||||
} catch (Exception $e) {
|
||||
//Do nothing
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a response from the POP3 server.
|
||||
* $size is the maximum number of bytes to retrieve
|
||||
* @param integer $size
|
||||
* @return string
|
||||
* @access protected
|
||||
*/
|
||||
protected function getResponse($size = 128)
|
||||
{
|
||||
$response = fgets($this->pop_conn, $size);
|
||||
if ($this->do_debug >= 1) {
|
||||
echo "Server -> Client: $response";
|
||||
}
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send raw data to the POP3 server.
|
||||
* @param string $string
|
||||
* @return integer
|
||||
* @access protected
|
||||
*/
|
||||
protected function sendString($string)
|
||||
{
|
||||
if ($this->pop_conn) {
|
||||
if ($this->do_debug >= 2) { //Show client messages when debug >= 2
|
||||
echo "Client -> Server: $string";
|
||||
}
|
||||
return fwrite($this->pop_conn, $string, strlen($string));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the POP3 server response.
|
||||
* Looks for for +OK or -ERR.
|
||||
* @param string $string
|
||||
* @return boolean
|
||||
* @access protected
|
||||
*/
|
||||
protected function checkResponse($string)
|
||||
{
|
||||
if (substr($string, 0, 3) !== '+OK') {
|
||||
$this->setError(array(
|
||||
'error' => "Server reported an error: $string",
|
||||
'errno' => 0,
|
||||
'errstr' => ''
|
||||
));
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an error to the internal error store.
|
||||
* Also display debug output if it's enabled.
|
||||
* @param $error
|
||||
* @access protected
|
||||
*/
|
||||
protected function setError($error)
|
||||
{
|
||||
$this->errors[] = $error;
|
||||
if ($this->do_debug >= 1) {
|
||||
echo '<pre>';
|
||||
foreach ($this->errors as $error) {
|
||||
print_r($error);
|
||||
}
|
||||
echo '</pre>';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array of error messages, if any.
|
||||
* @return array
|
||||
*/
|
||||
public function getErrors()
|
||||
{
|
||||
return $this->errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* POP3 connection error handler.
|
||||
* @param integer $errno
|
||||
* @param string $errstr
|
||||
* @param string $errfile
|
||||
* @param integer $errline
|
||||
* @access protected
|
||||
*/
|
||||
protected function catchWarning($errno, $errstr, $errfile, $errline)
|
||||
{
|
||||
$this->setError(array(
|
||||
'error' => "Connecting to the POP3 server raised a PHP warning: ",
|
||||
'errno' => $errno,
|
||||
'errstr' => $errstr,
|
||||
'errfile' => $errfile,
|
||||
'errline' => $errline
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -1,1276 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* PHPMailer RFC821 SMTP email transport class.
|
||||
* PHP Version 5
|
||||
* @package PHPMailer
|
||||
* @link https://github.com/PHPMailer/PHPMailer/ The PHPMailer GitHub project
|
||||
* @author Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk>
|
||||
* @author Jim Jagielski (jimjag) <jimjag@gmail.com>
|
||||
* @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net>
|
||||
* @author Brent R. Matzelle (original founder)
|
||||
* @copyright 2014 Marcus Bointon
|
||||
* @copyright 2010 - 2012 Jim Jagielski
|
||||
* @copyright 2004 - 2009 Andy Prevost
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
* @note This program is distributed in the hope that it will be useful - WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* PHPMailer RFC821 SMTP email transport class.
|
||||
* Implements RFC 821 SMTP commands and provides some utility methods for sending mail to an SMTP server.
|
||||
* @package PHPMailer
|
||||
* @author Chris Ryan
|
||||
* @author Marcus Bointon <phpmailer@synchromedia.co.uk>
|
||||
*/
|
||||
class SMTP
|
||||
{
|
||||
/**
|
||||
* The PHPMailer SMTP version number.
|
||||
* @var string
|
||||
*/
|
||||
const VERSION = '5.2.26';
|
||||
|
||||
/**
|
||||
* SMTP line break constant.
|
||||
* @var string
|
||||
*/
|
||||
const CRLF = "\r\n";
|
||||
|
||||
/**
|
||||
* The SMTP port to use if one is not specified.
|
||||
* @var integer
|
||||
*/
|
||||
const DEFAULT_SMTP_PORT = 25;
|
||||
|
||||
/**
|
||||
* The maximum line length allowed by RFC 2822 section 2.1.1
|
||||
* @var integer
|
||||
*/
|
||||
const MAX_LINE_LENGTH = 998;
|
||||
|
||||
/**
|
||||
* Debug level for no output
|
||||
*/
|
||||
const DEBUG_OFF = 0;
|
||||
|
||||
/**
|
||||
* Debug level to show client -> server messages
|
||||
*/
|
||||
const DEBUG_CLIENT = 1;
|
||||
|
||||
/**
|
||||
* Debug level to show client -> server and server -> client messages
|
||||
*/
|
||||
const DEBUG_SERVER = 2;
|
||||
|
||||
/**
|
||||
* Debug level to show connection status, client -> server and server -> client messages
|
||||
*/
|
||||
const DEBUG_CONNECTION = 3;
|
||||
|
||||
/**
|
||||
* Debug level to show all messages
|
||||
*/
|
||||
const DEBUG_LOWLEVEL = 4;
|
||||
|
||||
/**
|
||||
* The PHPMailer SMTP Version number.
|
||||
* @var string
|
||||
* @deprecated Use the `VERSION` constant instead
|
||||
* @see SMTP::VERSION
|
||||
*/
|
||||
public $Version = '5.2.26';
|
||||
|
||||
/**
|
||||
* SMTP server port number.
|
||||
* @var integer
|
||||
* @deprecated This is only ever used as a default value, so use the `DEFAULT_SMTP_PORT` constant instead
|
||||
* @see SMTP::DEFAULT_SMTP_PORT
|
||||
*/
|
||||
public $SMTP_PORT = 25;
|
||||
|
||||
/**
|
||||
* SMTP reply line ending.
|
||||
* @var string
|
||||
* @deprecated Use the `CRLF` constant instead
|
||||
* @see SMTP::CRLF
|
||||
*/
|
||||
public $CRLF = "\r\n";
|
||||
|
||||
/**
|
||||
* Debug output level.
|
||||
* Options:
|
||||
* * self::DEBUG_OFF (`0`) No debug output, default
|
||||
* * self::DEBUG_CLIENT (`1`) Client commands
|
||||
* * self::DEBUG_SERVER (`2`) Client commands and server responses
|
||||
* * self::DEBUG_CONNECTION (`3`) As DEBUG_SERVER plus connection status
|
||||
* * self::DEBUG_LOWLEVEL (`4`) Low-level data output, all messages
|
||||
* @var integer
|
||||
*/
|
||||
public $do_debug = self::DEBUG_OFF;
|
||||
|
||||
/**
|
||||
* How to handle debug output.
|
||||
* Options:
|
||||
* * `echo` Output plain-text as-is, appropriate for CLI
|
||||
* * `html` Output escaped, line breaks converted to `<br>`, appropriate for browser output
|
||||
* * `error_log` Output to error log as configured in php.ini
|
||||
*
|
||||
* Alternatively, you can provide a callable expecting two params: a message string and the debug level:
|
||||
* <code>
|
||||
* $smtp->Debugoutput = function($str, $level) {echo "debug level $level; message: $str";};
|
||||
* </code>
|
||||
* @var string|callable
|
||||
*/
|
||||
public $Debugoutput = 'echo';
|
||||
|
||||
/**
|
||||
* Whether to use VERP.
|
||||
* @link http://en.wikipedia.org/wiki/Variable_envelope_return_path
|
||||
* @link http://www.postfix.org/VERP_README.html Info on VERP
|
||||
* @var boolean
|
||||
*/
|
||||
public $do_verp = false;
|
||||
|
||||
/**
|
||||
* The timeout value for connection, in seconds.
|
||||
* Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2
|
||||
* This needs to be quite high to function correctly with hosts using greetdelay as an anti-spam measure.
|
||||
* @link http://tools.ietf.org/html/rfc2821#section-4.5.3.2
|
||||
* @var integer
|
||||
*/
|
||||
public $Timeout = 300;
|
||||
|
||||
/**
|
||||
* How long to wait for commands to complete, in seconds.
|
||||
* Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2
|
||||
* @var integer
|
||||
*/
|
||||
public $Timelimit = 300;
|
||||
|
||||
/**
|
||||
* @var array Patterns to extract an SMTP transaction id from reply to a DATA command.
|
||||
* The first capture group in each regex will be used as the ID.
|
||||
*/
|
||||
protected $smtp_transaction_id_patterns = array(
|
||||
'exim' => '/[0-9]{3} OK id=(.*)/',
|
||||
'sendmail' => '/[0-9]{3} 2.0.0 (.*) Message/',
|
||||
'postfix' => '/[0-9]{3} 2.0.0 Ok: queued as (.*)/'
|
||||
);
|
||||
|
||||
/**
|
||||
* @var string The last transaction ID issued in response to a DATA command,
|
||||
* if one was detected
|
||||
*/
|
||||
protected $last_smtp_transaction_id;
|
||||
|
||||
/**
|
||||
* The socket for the server connection.
|
||||
* @var resource
|
||||
*/
|
||||
protected $smtp_conn;
|
||||
|
||||
/**
|
||||
* Error information, if any, for the last SMTP command.
|
||||
* @var array
|
||||
*/
|
||||
protected $error = array(
|
||||
'error' => '',
|
||||
'detail' => '',
|
||||
'smtp_code' => '',
|
||||
'smtp_code_ex' => ''
|
||||
);
|
||||
|
||||
/**
|
||||
* The reply the server sent to us for HELO.
|
||||
* If null, no HELO string has yet been received.
|
||||
* @var string|null
|
||||
*/
|
||||
protected $helo_rply = null;
|
||||
|
||||
/**
|
||||
* The set of SMTP extensions sent in reply to EHLO command.
|
||||
* Indexes of the array are extension names.
|
||||
* Value at index 'HELO' or 'EHLO' (according to command that was sent)
|
||||
* represents the server name. In case of HELO it is the only element of the array.
|
||||
* Other values can be boolean TRUE or an array containing extension options.
|
||||
* If null, no HELO/EHLO string has yet been received.
|
||||
* @var array|null
|
||||
*/
|
||||
protected $server_caps = null;
|
||||
|
||||
/**
|
||||
* The most recent reply received from the server.
|
||||
* @var string
|
||||
*/
|
||||
protected $last_reply = '';
|
||||
|
||||
/**
|
||||
* Output debugging info via a user-selected method.
|
||||
* @see SMTP::$Debugoutput
|
||||
* @see SMTP::$do_debug
|
||||
* @param string $str Debug string to output
|
||||
* @param integer $level The debug level of this message; see DEBUG_* constants
|
||||
* @return void
|
||||
*/
|
||||
protected function edebug($str, $level = 0)
|
||||
{
|
||||
if ($level > $this->do_debug) {
|
||||
return;
|
||||
}
|
||||
//Avoid clash with built-in function names
|
||||
if (!in_array($this->Debugoutput, array('error_log', 'html', 'echo')) and is_callable($this->Debugoutput)) {
|
||||
call_user_func($this->Debugoutput, $str, $level);
|
||||
return;
|
||||
}
|
||||
switch ($this->Debugoutput) {
|
||||
case 'error_log':
|
||||
//Don't output, just log
|
||||
error_log($str);
|
||||
break;
|
||||
case 'html':
|
||||
//Cleans up output a bit for a better looking, HTML-safe output
|
||||
echo gmdate('Y-m-d H:i:s') . ' ' . htmlentities(
|
||||
preg_replace('/[\r\n]+/', '', $str),
|
||||
ENT_QUOTES,
|
||||
'UTF-8'
|
||||
) . "<br>\n";
|
||||
break;
|
||||
case 'echo':
|
||||
default:
|
||||
//Normalize line breaks
|
||||
$str = preg_replace('/(\r\n|\r|\n)/ms', "\n", $str);
|
||||
echo gmdate('Y-m-d H:i:s') . "\t" . str_replace(
|
||||
"\n",
|
||||
"\n \t ",
|
||||
trim($str)
|
||||
) . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect to an SMTP server.
|
||||
* @param string $host SMTP server IP or host name
|
||||
* @param integer $port The port number to connect to
|
||||
* @param integer $timeout How long to wait for the connection to open
|
||||
* @param array $options An array of options for stream_context_create()
|
||||
* @access public
|
||||
* @return boolean
|
||||
*/
|
||||
public function connect($host, $port = null, $timeout = 30, $options = array())
|
||||
{
|
||||
static $streamok;
|
||||
//This is enabled by default since 5.0.0 but some providers disable it
|
||||
//Check this once and cache the result
|
||||
if (is_null($streamok)) {
|
||||
$streamok = function_exists('stream_socket_client');
|
||||
}
|
||||
// Clear errors to avoid confusion
|
||||
$this->setError('');
|
||||
// Make sure we are __not__ connected
|
||||
if ($this->connected()) {
|
||||
// Already connected, generate error
|
||||
$this->setError('Already connected to a server');
|
||||
return false;
|
||||
}
|
||||
if (empty($port)) {
|
||||
$port = self::DEFAULT_SMTP_PORT;
|
||||
}
|
||||
// Connect to the SMTP server
|
||||
$this->edebug(
|
||||
"Connection: opening to $host:$port, timeout=$timeout, options=" .
|
||||
var_export($options, true),
|
||||
self::DEBUG_CONNECTION
|
||||
);
|
||||
$errno = 0;
|
||||
$errstr = '';
|
||||
if ($streamok) {
|
||||
$socket_context = stream_context_create($options);
|
||||
set_error_handler(array($this, 'errorHandler'));
|
||||
$this->smtp_conn = stream_socket_client(
|
||||
$host . ":" . $port,
|
||||
$errno,
|
||||
$errstr,
|
||||
$timeout,
|
||||
STREAM_CLIENT_CONNECT,
|
||||
$socket_context
|
||||
);
|
||||
restore_error_handler();
|
||||
} else {
|
||||
//Fall back to fsockopen which should work in more places, but is missing some features
|
||||
$this->edebug(
|
||||
"Connection: stream_socket_client not available, falling back to fsockopen",
|
||||
self::DEBUG_CONNECTION
|
||||
);
|
||||
set_error_handler(array($this, 'errorHandler'));
|
||||
$this->smtp_conn = fsockopen(
|
||||
$host,
|
||||
$port,
|
||||
$errno,
|
||||
$errstr,
|
||||
$timeout
|
||||
);
|
||||
restore_error_handler();
|
||||
}
|
||||
// Verify we connected properly
|
||||
if (!is_resource($this->smtp_conn)) {
|
||||
$this->setError(
|
||||
'Failed to connect to server',
|
||||
$errno,
|
||||
$errstr
|
||||
);
|
||||
$this->edebug(
|
||||
'SMTP ERROR: ' . $this->error['error']
|
||||
. ": $errstr ($errno)",
|
||||
self::DEBUG_CLIENT
|
||||
);
|
||||
return false;
|
||||
}
|
||||
$this->edebug('Connection: opened', self::DEBUG_CONNECTION);
|
||||
// SMTP server can take longer to respond, give longer timeout for first read
|
||||
// Windows does not have support for this timeout function
|
||||
if (substr(PHP_OS, 0, 3) != 'WIN') {
|
||||
$max = ini_get('max_execution_time');
|
||||
// Don't bother if unlimited
|
||||
if ($max != 0 && $timeout > $max) {
|
||||
@set_time_limit($timeout);
|
||||
}
|
||||
stream_set_timeout($this->smtp_conn, $timeout, 0);
|
||||
}
|
||||
// Get any announcement
|
||||
$announce = $this->get_lines();
|
||||
$this->edebug('SERVER -> CLIENT: ' . $announce, self::DEBUG_SERVER);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiate a TLS (encrypted) session.
|
||||
* @access public
|
||||
* @return boolean
|
||||
*/
|
||||
public function startTLS()
|
||||
{
|
||||
if (!$this->sendCommand('STARTTLS', 'STARTTLS', 220)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//Allow the best TLS version(s) we can
|
||||
$crypto_method = STREAM_CRYPTO_METHOD_TLS_CLIENT;
|
||||
|
||||
//PHP 5.6.7 dropped inclusion of TLS 1.1 and 1.2 in STREAM_CRYPTO_METHOD_TLS_CLIENT
|
||||
//so add them back in manually if we can
|
||||
if (defined('STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT')) {
|
||||
$crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT;
|
||||
$crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT;
|
||||
}
|
||||
|
||||
// Begin encrypted connection
|
||||
set_error_handler(array($this, 'errorHandler'));
|
||||
$crypto_ok = stream_socket_enable_crypto(
|
||||
$this->smtp_conn,
|
||||
true,
|
||||
$crypto_method
|
||||
);
|
||||
restore_error_handler();
|
||||
return $crypto_ok;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform SMTP authentication.
|
||||
* Must be run after hello().
|
||||
* @see hello()
|
||||
* @param string $username The user name
|
||||
* @param string $password The password
|
||||
* @param string $authtype The auth type (PLAIN, LOGIN, NTLM, CRAM-MD5, XOAUTH2)
|
||||
* @param string $realm The auth realm for NTLM
|
||||
* @param string $workstation The auth workstation for NTLM
|
||||
* @param null|OAuth $OAuth An optional OAuth instance (@see PHPMailerOAuth)
|
||||
* @return bool True if successfully authenticated.* @access public
|
||||
*/
|
||||
public function authenticate(
|
||||
$username,
|
||||
$password,
|
||||
$authtype = null,
|
||||
$realm = '',
|
||||
$workstation = '',
|
||||
$OAuth = null
|
||||
) {
|
||||
if (!$this->server_caps) {
|
||||
$this->setError('Authentication is not allowed before HELO/EHLO');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (array_key_exists('EHLO', $this->server_caps)) {
|
||||
// SMTP extensions are available; try to find a proper authentication method
|
||||
if (!array_key_exists('AUTH', $this->server_caps)) {
|
||||
$this->setError('Authentication is not allowed at this stage');
|
||||
// 'at this stage' means that auth may be allowed after the stage changes
|
||||
// e.g. after STARTTLS
|
||||
return false;
|
||||
}
|
||||
|
||||
self::edebug('Auth method requested: ' . ($authtype ? $authtype : 'UNKNOWN'), self::DEBUG_LOWLEVEL);
|
||||
self::edebug(
|
||||
'Auth methods available on the server: ' . implode(',', $this->server_caps['AUTH']),
|
||||
self::DEBUG_LOWLEVEL
|
||||
);
|
||||
|
||||
if (empty($authtype)) {
|
||||
foreach (array('CRAM-MD5', 'LOGIN', 'PLAIN', 'NTLM', 'XOAUTH2') as $method) {
|
||||
if (in_array($method, $this->server_caps['AUTH'])) {
|
||||
$authtype = $method;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (empty($authtype)) {
|
||||
$this->setError('No supported authentication methods found');
|
||||
return false;
|
||||
}
|
||||
self::edebug('Auth method selected: ' . $authtype, self::DEBUG_LOWLEVEL);
|
||||
}
|
||||
|
||||
if (!in_array($authtype, $this->server_caps['AUTH'])) {
|
||||
$this->setError("The requested authentication method \"$authtype\" is not supported by the server");
|
||||
return false;
|
||||
}
|
||||
} elseif (empty($authtype)) {
|
||||
$authtype = 'LOGIN';
|
||||
}
|
||||
switch ($authtype) {
|
||||
case 'PLAIN':
|
||||
// Start authentication
|
||||
if (!$this->sendCommand('AUTH', 'AUTH PLAIN', 334)) {
|
||||
return false;
|
||||
}
|
||||
// Send encoded username and password
|
||||
if (!$this->sendCommand(
|
||||
'User & Password',
|
||||
base64_encode("\0" . $username . "\0" . $password),
|
||||
235
|
||||
)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case 'LOGIN':
|
||||
// Start authentication
|
||||
if (!$this->sendCommand('AUTH', 'AUTH LOGIN', 334)) {
|
||||
return false;
|
||||
}
|
||||
if (!$this->sendCommand("Username", base64_encode($username), 334)) {
|
||||
return false;
|
||||
}
|
||||
if (!$this->sendCommand("Password", base64_encode($password), 235)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case 'XOAUTH2':
|
||||
//If the OAuth Instance is not set. Can be a case when PHPMailer is used
|
||||
//instead of PHPMailerOAuth
|
||||
if (is_null($OAuth)) {
|
||||
return false;
|
||||
}
|
||||
$oauth = $OAuth->getOauth64();
|
||||
|
||||
// Start authentication
|
||||
if (!$this->sendCommand('AUTH', 'AUTH XOAUTH2 ' . $oauth, 235)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case 'NTLM':
|
||||
/*
|
||||
* ntlm_sasl_client.php
|
||||
* Bundled with Permission
|
||||
*
|
||||
* How to telnet in windows:
|
||||
* http://technet.microsoft.com/en-us/library/aa995718%28EXCHG.65%29.aspx
|
||||
* PROTOCOL Docs http://curl.haxx.se/rfc/ntlm.html#ntlmSmtpAuthentication
|
||||
*/
|
||||
require_once 'extras/ntlm_sasl_client.php';
|
||||
$temp = new stdClass;
|
||||
$ntlm_client = new ntlm_sasl_client_class;
|
||||
//Check that functions are available
|
||||
if (!$ntlm_client->initialize($temp)) {
|
||||
$this->setError($temp->error);
|
||||
$this->edebug(
|
||||
'You need to enable some modules in your php.ini file: '
|
||||
. $this->error['error'],
|
||||
self::DEBUG_CLIENT
|
||||
);
|
||||
return false;
|
||||
}
|
||||
//msg1
|
||||
$msg1 = $ntlm_client->typeMsg1($realm, $workstation); //msg1
|
||||
|
||||
if (!$this->sendCommand(
|
||||
'AUTH NTLM',
|
||||
'AUTH NTLM ' . base64_encode($msg1),
|
||||
334
|
||||
)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
//Though 0 based, there is a white space after the 3 digit number
|
||||
//msg2
|
||||
$challenge = substr($this->last_reply, 3);
|
||||
$challenge = base64_decode($challenge);
|
||||
$ntlm_res = $ntlm_client->NTLMResponse(
|
||||
substr($challenge, 24, 8),
|
||||
$password
|
||||
);
|
||||
//msg3
|
||||
$msg3 = $ntlm_client->typeMsg3(
|
||||
$ntlm_res,
|
||||
$username,
|
||||
$realm,
|
||||
$workstation
|
||||
);
|
||||
// send encoded username
|
||||
return $this->sendCommand('Username', base64_encode($msg3), 235);
|
||||
case 'CRAM-MD5':
|
||||
// Start authentication
|
||||
if (!$this->sendCommand('AUTH CRAM-MD5', 'AUTH CRAM-MD5', 334)) {
|
||||
return false;
|
||||
}
|
||||
// Get the challenge
|
||||
$challenge = base64_decode(substr($this->last_reply, 4));
|
||||
|
||||
// Build the response
|
||||
$response = $username . ' ' . $this->hmac($challenge, $password);
|
||||
|
||||
// send encoded credentials
|
||||
return $this->sendCommand('Username', base64_encode($response), 235);
|
||||
default:
|
||||
$this->setError("Authentication method \"$authtype\" is not supported");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate an MD5 HMAC hash.
|
||||
* Works like hash_hmac('md5', $data, $key)
|
||||
* in case that function is not available
|
||||
* @param string $data The data to hash
|
||||
* @param string $key The key to hash with
|
||||
* @access protected
|
||||
* @return string
|
||||
*/
|
||||
protected function hmac($data, $key)
|
||||
{
|
||||
if (function_exists('hash_hmac')) {
|
||||
return hash_hmac('md5', $data, $key);
|
||||
}
|
||||
|
||||
// The following borrowed from
|
||||
// http://php.net/manual/en/function.mhash.php#27225
|
||||
|
||||
// RFC 2104 HMAC implementation for php.
|
||||
// Creates an md5 HMAC.
|
||||
// Eliminates the need to install mhash to compute a HMAC
|
||||
// by Lance Rushing
|
||||
|
||||
$bytelen = 64; // byte length for md5
|
||||
if (strlen($key) > $bytelen) {
|
||||
$key = pack('H*', md5($key));
|
||||
}
|
||||
$key = str_pad($key, $bytelen, chr(0x00));
|
||||
$ipad = str_pad('', $bytelen, chr(0x36));
|
||||
$opad = str_pad('', $bytelen, chr(0x5c));
|
||||
$k_ipad = $key ^ $ipad;
|
||||
$k_opad = $key ^ $opad;
|
||||
|
||||
return md5($k_opad . pack('H*', md5($k_ipad . $data)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check connection state.
|
||||
* @access public
|
||||
* @return boolean True if connected.
|
||||
*/
|
||||
public function connected()
|
||||
{
|
||||
if (is_resource($this->smtp_conn)) {
|
||||
$sock_status = stream_get_meta_data($this->smtp_conn);
|
||||
if ($sock_status['eof']) {
|
||||
// The socket is valid but we are not connected
|
||||
$this->edebug(
|
||||
'SMTP NOTICE: EOF caught while checking if connected',
|
||||
self::DEBUG_CLIENT
|
||||
);
|
||||
$this->close();
|
||||
return false;
|
||||
}
|
||||
return true; // everything looks good
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the socket and clean up the state of the class.
|
||||
* Don't use this function without first trying to use QUIT.
|
||||
* @see quit()
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
$this->setError('');
|
||||
$this->server_caps = null;
|
||||
$this->helo_rply = null;
|
||||
if (is_resource($this->smtp_conn)) {
|
||||
// close the connection and cleanup
|
||||
fclose($this->smtp_conn);
|
||||
$this->smtp_conn = null; //Makes for cleaner serialization
|
||||
$this->edebug('Connection: closed', self::DEBUG_CONNECTION);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an SMTP DATA command.
|
||||
* Issues a data command and sends the msg_data to the server,
|
||||
* finializing the mail transaction. $msg_data is the message
|
||||
* that is to be send with the headers. Each header needs to be
|
||||
* on a single line followed by a <CRLF> with the message headers
|
||||
* and the message body being separated by and additional <CRLF>.
|
||||
* Implements rfc 821: DATA <CRLF>
|
||||
* @param string $msg_data Message data to send
|
||||
* @access public
|
||||
* @return boolean
|
||||
*/
|
||||
public function data($msg_data)
|
||||
{
|
||||
//This will use the standard timelimit
|
||||
if (!$this->sendCommand('DATA', 'DATA', 354)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* The server is ready to accept data!
|
||||
* According to rfc821 we should not send more than 1000 characters on a single line (including the CRLF)
|
||||
* so we will break the data up into lines by \r and/or \n then if needed we will break each of those into
|
||||
* smaller lines to fit within the limit.
|
||||
* We will also look for lines that start with a '.' and prepend an additional '.'.
|
||||
* NOTE: this does not count towards line-length limit.
|
||||
*/
|
||||
|
||||
// Normalize line breaks before exploding
|
||||
$lines = explode("\n", str_replace(array("\r\n", "\r"), "\n", $msg_data));
|
||||
|
||||
/* To distinguish between a complete RFC822 message and a plain message body, we check if the first field
|
||||
* of the first line (':' separated) does not contain a space then it _should_ be a header and we will
|
||||
* process all lines before a blank line as headers.
|
||||
*/
|
||||
|
||||
$field = substr($lines[0], 0, strpos($lines[0], ':'));
|
||||
$in_headers = false;
|
||||
if (!empty($field) && strpos($field, ' ') === false) {
|
||||
$in_headers = true;
|
||||
}
|
||||
|
||||
foreach ($lines as $line) {
|
||||
$lines_out = array();
|
||||
if ($in_headers and $line == '') {
|
||||
$in_headers = false;
|
||||
}
|
||||
//Break this line up into several smaller lines if it's too long
|
||||
//Micro-optimisation: isset($str[$len]) is faster than (strlen($str) > $len),
|
||||
while (isset($line[self::MAX_LINE_LENGTH])) {
|
||||
//Working backwards, try to find a space within the last MAX_LINE_LENGTH chars of the line to break on
|
||||
//so as to avoid breaking in the middle of a word
|
||||
$pos = strrpos(substr($line, 0, self::MAX_LINE_LENGTH), ' ');
|
||||
//Deliberately matches both false and 0
|
||||
if (!$pos) {
|
||||
//No nice break found, add a hard break
|
||||
$pos = self::MAX_LINE_LENGTH - 1;
|
||||
$lines_out[] = substr($line, 0, $pos);
|
||||
$line = substr($line, $pos);
|
||||
} else {
|
||||
//Break at the found point
|
||||
$lines_out[] = substr($line, 0, $pos);
|
||||
//Move along by the amount we dealt with
|
||||
$line = substr($line, $pos + 1);
|
||||
}
|
||||
//If processing headers add a LWSP-char to the front of new line RFC822 section 3.1.1
|
||||
if ($in_headers) {
|
||||
$line = "\t" . $line;
|
||||
}
|
||||
}
|
||||
$lines_out[] = $line;
|
||||
|
||||
//Send the lines to the server
|
||||
foreach ($lines_out as $line_out) {
|
||||
//RFC2821 section 4.5.2
|
||||
if (!empty($line_out) and $line_out[0] == '.') {
|
||||
$line_out = '.' . $line_out;
|
||||
}
|
||||
$this->client_send($line_out . self::CRLF);
|
||||
}
|
||||
}
|
||||
|
||||
//Message data has been sent, complete the command
|
||||
//Increase timelimit for end of DATA command
|
||||
$savetimelimit = $this->Timelimit;
|
||||
$this->Timelimit = $this->Timelimit * 2;
|
||||
$result = $this->sendCommand('DATA END', '.', 250);
|
||||
$this->recordLastTransactionID();
|
||||
//Restore timelimit
|
||||
$this->Timelimit = $savetimelimit;
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an SMTP HELO or EHLO command.
|
||||
* Used to identify the sending server to the receiving server.
|
||||
* This makes sure that client and server are in a known state.
|
||||
* Implements RFC 821: HELO <SP> <domain> <CRLF>
|
||||
* and RFC 2821 EHLO.
|
||||
* @param string $host The host name or IP to connect to
|
||||
* @access public
|
||||
* @return boolean
|
||||
*/
|
||||
public function hello($host = '')
|
||||
{
|
||||
//Try extended hello first (RFC 2821)
|
||||
return (boolean)($this->sendHello('EHLO', $host) or $this->sendHello('HELO', $host));
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an SMTP HELO or EHLO command.
|
||||
* Low-level implementation used by hello()
|
||||
* @see hello()
|
||||
* @param string $hello The HELO string
|
||||
* @param string $host The hostname to say we are
|
||||
* @access protected
|
||||
* @return boolean
|
||||
*/
|
||||
protected function sendHello($hello, $host)
|
||||
{
|
||||
$noerror = $this->sendCommand($hello, $hello . ' ' . $host, 250);
|
||||
$this->helo_rply = $this->last_reply;
|
||||
if ($noerror) {
|
||||
$this->parseHelloFields($hello);
|
||||
} else {
|
||||
$this->server_caps = null;
|
||||
}
|
||||
return $noerror;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a reply to HELO/EHLO command to discover server extensions.
|
||||
* In case of HELO, the only parameter that can be discovered is a server name.
|
||||
* @access protected
|
||||
* @param string $type - 'HELO' or 'EHLO'
|
||||
*/
|
||||
protected function parseHelloFields($type)
|
||||
{
|
||||
$this->server_caps = array();
|
||||
$lines = explode("\n", $this->helo_rply);
|
||||
|
||||
foreach ($lines as $n => $s) {
|
||||
//First 4 chars contain response code followed by - or space
|
||||
$s = trim(substr($s, 4));
|
||||
if (empty($s)) {
|
||||
continue;
|
||||
}
|
||||
$fields = explode(' ', $s);
|
||||
if (!empty($fields)) {
|
||||
if (!$n) {
|
||||
$name = $type;
|
||||
$fields = $fields[0];
|
||||
} else {
|
||||
$name = array_shift($fields);
|
||||
switch ($name) {
|
||||
case 'SIZE':
|
||||
$fields = ($fields ? $fields[0] : 0);
|
||||
break;
|
||||
case 'AUTH':
|
||||
if (!is_array($fields)) {
|
||||
$fields = array();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
$fields = true;
|
||||
}
|
||||
}
|
||||
$this->server_caps[$name] = $fields;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an SMTP MAIL command.
|
||||
* Starts a mail transaction from the email address specified in
|
||||
* $from. Returns true if successful or false otherwise. If True
|
||||
* the mail transaction is started and then one or more recipient
|
||||
* commands may be called followed by a data command.
|
||||
* Implements rfc 821: MAIL <SP> FROM:<reverse-path> <CRLF>
|
||||
* @param string $from Source address of this message
|
||||
* @access public
|
||||
* @return boolean
|
||||
*/
|
||||
public function mail($from)
|
||||
{
|
||||
$useVerp = ($this->do_verp ? ' XVERP' : '');
|
||||
return $this->sendCommand(
|
||||
'MAIL FROM',
|
||||
'MAIL FROM:<' . $from . '>' . $useVerp,
|
||||
250
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an SMTP QUIT command.
|
||||
* Closes the socket if there is no error or the $close_on_error argument is true.
|
||||
* Implements from rfc 821: QUIT <CRLF>
|
||||
* @param boolean $close_on_error Should the connection close if an error occurs?
|
||||
* @access public
|
||||
* @return boolean
|
||||
*/
|
||||
public function quit($close_on_error = true)
|
||||
{
|
||||
$noerror = $this->sendCommand('QUIT', 'QUIT', 221);
|
||||
$err = $this->error; //Save any error
|
||||
if ($noerror or $close_on_error) {
|
||||
$this->close();
|
||||
$this->error = $err; //Restore any error from the quit command
|
||||
}
|
||||
return $noerror;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an SMTP RCPT command.
|
||||
* Sets the TO argument to $toaddr.
|
||||
* Returns true if the recipient was accepted false if it was rejected.
|
||||
* Implements from rfc 821: RCPT <SP> TO:<forward-path> <CRLF>
|
||||
* @param string $address The address the message is being sent to
|
||||
* @access public
|
||||
* @return boolean
|
||||
*/
|
||||
public function recipient($address)
|
||||
{
|
||||
return $this->sendCommand(
|
||||
'RCPT TO',
|
||||
'RCPT TO:<' . $address . '>',
|
||||
array(250, 251)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an SMTP RSET command.
|
||||
* Abort any transaction that is currently in progress.
|
||||
* Implements rfc 821: RSET <CRLF>
|
||||
* @access public
|
||||
* @return boolean True on success.
|
||||
*/
|
||||
public function reset()
|
||||
{
|
||||
return $this->sendCommand('RSET', 'RSET', 250);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a command to an SMTP server and check its return code.
|
||||
* @param string $command The command name - not sent to the server
|
||||
* @param string $commandstring The actual command to send
|
||||
* @param integer|array $expect One or more expected integer success codes
|
||||
* @access protected
|
||||
* @return boolean True on success.
|
||||
*/
|
||||
protected function sendCommand($command, $commandstring, $expect)
|
||||
{
|
||||
if (!$this->connected()) {
|
||||
$this->setError("Called $command without being connected");
|
||||
return false;
|
||||
}
|
||||
//Reject line breaks in all commands
|
||||
if (strpos($commandstring, "\n") !== false or strpos($commandstring, "\r") !== false) {
|
||||
$this->setError("Command '$command' contained line breaks");
|
||||
return false;
|
||||
}
|
||||
$this->client_send($commandstring . self::CRLF);
|
||||
|
||||
$this->last_reply = $this->get_lines();
|
||||
// Fetch SMTP code and possible error code explanation
|
||||
$matches = array();
|
||||
if (preg_match("/^([0-9]{3})[ -](?:([0-9]\\.[0-9]\\.[0-9]) )?/", $this->last_reply, $matches)) {
|
||||
$code = $matches[1];
|
||||
$code_ex = (count($matches) > 2 ? $matches[2] : null);
|
||||
// Cut off error code from each response line
|
||||
$detail = preg_replace(
|
||||
"/{$code}[ -]" .
|
||||
($code_ex ? str_replace('.', '\\.', $code_ex) . ' ' : '') . "/m",
|
||||
'',
|
||||
$this->last_reply
|
||||
);
|
||||
} else {
|
||||
// Fall back to simple parsing if regex fails
|
||||
$code = substr($this->last_reply, 0, 3);
|
||||
$code_ex = null;
|
||||
$detail = substr($this->last_reply, 4);
|
||||
}
|
||||
|
||||
$this->edebug('SERVER -> CLIENT: ' . $this->last_reply, self::DEBUG_SERVER);
|
||||
|
||||
if (!in_array($code, (array)$expect)) {
|
||||
$this->setError(
|
||||
"$command command failed",
|
||||
$detail,
|
||||
$code,
|
||||
$code_ex
|
||||
);
|
||||
$this->edebug(
|
||||
'SMTP ERROR: ' . $this->error['error'] . ': ' . $this->last_reply,
|
||||
self::DEBUG_CLIENT
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->setError('');
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an SMTP SAML command.
|
||||
* Starts a mail transaction from the email address specified in $from.
|
||||
* Returns true if successful or false otherwise. If True
|
||||
* the mail transaction is started and then one or more recipient
|
||||
* commands may be called followed by a data command. This command
|
||||
* will send the message to the users terminal if they are logged
|
||||
* in and send them an email.
|
||||
* Implements rfc 821: SAML <SP> FROM:<reverse-path> <CRLF>
|
||||
* @param string $from The address the message is from
|
||||
* @access public
|
||||
* @return boolean
|
||||
*/
|
||||
public function sendAndMail($from)
|
||||
{
|
||||
return $this->sendCommand('SAML', "SAML FROM:$from", 250);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an SMTP VRFY command.
|
||||
* @param string $name The name to verify
|
||||
* @access public
|
||||
* @return boolean
|
||||
*/
|
||||
public function verify($name)
|
||||
{
|
||||
return $this->sendCommand('VRFY', "VRFY $name", array(250, 251));
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an SMTP NOOP command.
|
||||
* Used to keep keep-alives alive, doesn't actually do anything
|
||||
* @access public
|
||||
* @return boolean
|
||||
*/
|
||||
public function noop()
|
||||
{
|
||||
return $this->sendCommand('NOOP', 'NOOP', 250);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an SMTP TURN command.
|
||||
* This is an optional command for SMTP that this class does not support.
|
||||
* This method is here to make the RFC821 Definition complete for this class
|
||||
* and _may_ be implemented in future
|
||||
* Implements from rfc 821: TURN <CRLF>
|
||||
* @access public
|
||||
* @return boolean
|
||||
*/
|
||||
public function turn()
|
||||
{
|
||||
$this->setError('The SMTP TURN command is not implemented');
|
||||
$this->edebug('SMTP NOTICE: ' . $this->error['error'], self::DEBUG_CLIENT);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send raw data to the server.
|
||||
* @param string $data The data to send
|
||||
* @access public
|
||||
* @return integer|boolean The number of bytes sent to the server or false on error
|
||||
*/
|
||||
public function client_send($data)
|
||||
{
|
||||
$this->edebug("CLIENT -> SERVER: $data", self::DEBUG_CLIENT);
|
||||
set_error_handler(array($this, 'errorHandler'));
|
||||
$result = fwrite($this->smtp_conn, $data);
|
||||
restore_error_handler();
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the latest error.
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getError()
|
||||
{
|
||||
return $this->error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get SMTP extensions available on the server
|
||||
* @access public
|
||||
* @return array|null
|
||||
*/
|
||||
public function getServerExtList()
|
||||
{
|
||||
return $this->server_caps;
|
||||
}
|
||||
|
||||
/**
|
||||
* A multipurpose method
|
||||
* The method works in three ways, dependent on argument value and current state
|
||||
* 1. HELO/EHLO was not sent - returns null and set up $this->error
|
||||
* 2. HELO was sent
|
||||
* $name = 'HELO': returns server name
|
||||
* $name = 'EHLO': returns boolean false
|
||||
* $name = any string: returns null and set up $this->error
|
||||
* 3. EHLO was sent
|
||||
* $name = 'HELO'|'EHLO': returns server name
|
||||
* $name = any string: if extension $name exists, returns boolean True
|
||||
* or its options. Otherwise returns boolean False
|
||||
* In other words, one can use this method to detect 3 conditions:
|
||||
* - null returned: handshake was not or we don't know about ext (refer to $this->error)
|
||||
* - false returned: the requested feature exactly not exists
|
||||
* - positive value returned: the requested feature exists
|
||||
* @param string $name Name of SMTP extension or 'HELO'|'EHLO'
|
||||
* @return mixed
|
||||
*/
|
||||
public function getServerExt($name)
|
||||
{
|
||||
if (!$this->server_caps) {
|
||||
$this->setError('No HELO/EHLO was sent');
|
||||
return null;
|
||||
}
|
||||
|
||||
// the tight logic knot ;)
|
||||
if (!array_key_exists($name, $this->server_caps)) {
|
||||
if ($name == 'HELO') {
|
||||
return $this->server_caps['EHLO'];
|
||||
}
|
||||
if ($name == 'EHLO' || array_key_exists('EHLO', $this->server_caps)) {
|
||||
return false;
|
||||
}
|
||||
$this->setError('HELO handshake was used. Client knows nothing about server extensions');
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->server_caps[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last reply from the server.
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getLastReply()
|
||||
{
|
||||
return $this->last_reply;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the SMTP server's response.
|
||||
* Either before eof or socket timeout occurs on the operation.
|
||||
* With SMTP we can tell if we have more lines to read if the
|
||||
* 4th character is '-' symbol. If it is a space then we don't
|
||||
* need to read anything else.
|
||||
* @access protected
|
||||
* @return string
|
||||
*/
|
||||
protected function get_lines()
|
||||
{
|
||||
// If the connection is bad, give up straight away
|
||||
if (!is_resource($this->smtp_conn)) {
|
||||
return '';
|
||||
}
|
||||
$data = '';
|
||||
$endtime = 0;
|
||||
stream_set_timeout($this->smtp_conn, $this->Timeout);
|
||||
if ($this->Timelimit > 0) {
|
||||
$endtime = time() + $this->Timelimit;
|
||||
}
|
||||
while (is_resource($this->smtp_conn) && !feof($this->smtp_conn)) {
|
||||
$str = @fgets($this->smtp_conn, 515);
|
||||
$this->edebug("SMTP -> get_lines(): \$data is \"$data\"", self::DEBUG_LOWLEVEL);
|
||||
$this->edebug("SMTP -> get_lines(): \$str is \"$str\"", self::DEBUG_LOWLEVEL);
|
||||
$data .= $str;
|
||||
// If response is only 3 chars (not valid, but RFC5321 S4.2 says it must be handled),
|
||||
// or 4th character is a space, we are done reading, break the loop,
|
||||
// string array access is a micro-optimisation over strlen
|
||||
if (!isset($str[3]) or (isset($str[3]) and $str[3] == ' ')) {
|
||||
break;
|
||||
}
|
||||
// Timed-out? Log and break
|
||||
$info = stream_get_meta_data($this->smtp_conn);
|
||||
if ($info['timed_out']) {
|
||||
$this->edebug(
|
||||
'SMTP -> get_lines(): timed-out (' . $this->Timeout . ' sec)',
|
||||
self::DEBUG_LOWLEVEL
|
||||
);
|
||||
break;
|
||||
}
|
||||
// Now check if reads took too long
|
||||
if ($endtime and time() > $endtime) {
|
||||
$this->edebug(
|
||||
'SMTP -> get_lines(): timelimit reached (' .
|
||||
$this->Timelimit . ' sec)',
|
||||
self::DEBUG_LOWLEVEL
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable or disable VERP address generation.
|
||||
* @param boolean $enabled
|
||||
*/
|
||||
public function setVerp($enabled = false)
|
||||
{
|
||||
$this->do_verp = $enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get VERP address generation mode.
|
||||
* @return boolean
|
||||
*/
|
||||
public function getVerp()
|
||||
{
|
||||
return $this->do_verp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set error messages and codes.
|
||||
* @param string $message The error message
|
||||
* @param string $detail Further detail on the error
|
||||
* @param string $smtp_code An associated SMTP error code
|
||||
* @param string $smtp_code_ex Extended SMTP code
|
||||
*/
|
||||
protected function setError($message, $detail = '', $smtp_code = '', $smtp_code_ex = '')
|
||||
{
|
||||
$this->error = array(
|
||||
'error' => $message,
|
||||
'detail' => $detail,
|
||||
'smtp_code' => $smtp_code,
|
||||
'smtp_code_ex' => $smtp_code_ex
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set debug output method.
|
||||
* @param string|callable $method The name of the mechanism to use for debugging output, or a callable to handle it.
|
||||
*/
|
||||
public function setDebugOutput($method = 'echo')
|
||||
{
|
||||
$this->Debugoutput = $method;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get debug output method.
|
||||
* @return string
|
||||
*/
|
||||
public function getDebugOutput()
|
||||
{
|
||||
return $this->Debugoutput;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set debug output level.
|
||||
* @param integer $level
|
||||
*/
|
||||
public function setDebugLevel($level = 0)
|
||||
{
|
||||
$this->do_debug = $level;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get debug output level.
|
||||
* @return integer
|
||||
*/
|
||||
public function getDebugLevel()
|
||||
{
|
||||
return $this->do_debug;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set SMTP timeout.
|
||||
* @param integer $timeout
|
||||
*/
|
||||
public function setTimeout($timeout = 0)
|
||||
{
|
||||
$this->Timeout = $timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get SMTP timeout.
|
||||
* @return integer
|
||||
*/
|
||||
public function getTimeout()
|
||||
{
|
||||
return $this->Timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports an error number and string.
|
||||
* @param integer $errno The error number returned by PHP.
|
||||
* @param string $errmsg The error message returned by PHP.
|
||||
* @param string $errfile The file the error occurred in
|
||||
* @param integer $errline The line number the error occurred on
|
||||
*/
|
||||
protected function errorHandler($errno, $errmsg, $errfile = '', $errline = 0)
|
||||
{
|
||||
$notice = 'Connection failed.';
|
||||
$this->setError(
|
||||
$notice,
|
||||
$errno,
|
||||
$errmsg
|
||||
);
|
||||
$this->edebug(
|
||||
$notice . ' Error #' . $errno . ': ' . $errmsg . " [$errfile line $errline]",
|
||||
self::DEBUG_CONNECTION
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract and return the ID of the last SMTP transaction based on
|
||||
* a list of patterns provided in SMTP::$smtp_transaction_id_patterns.
|
||||
* Relies on the host providing the ID in response to a DATA command.
|
||||
* If no reply has been received yet, it will return null.
|
||||
* If no pattern was matched, it will return false.
|
||||
* @return bool|null|string
|
||||
*/
|
||||
protected function recordLastTransactionID()
|
||||
{
|
||||
$reply = $this->getLastReply();
|
||||
|
||||
if (empty($reply)) {
|
||||
$this->last_smtp_transaction_id = null;
|
||||
} else {
|
||||
$this->last_smtp_transaction_id = false;
|
||||
foreach ($this->smtp_transaction_id_patterns as $smtp_transaction_id_pattern) {
|
||||
if (preg_match($smtp_transaction_id_pattern, $reply, $matches)) {
|
||||
$this->last_smtp_transaction_id = $matches[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->last_smtp_transaction_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the queue/transaction ID of the last SMTP transaction
|
||||
* If no reply has been received yet, it will return null.
|
||||
* If no pattern was matched, it will return false.
|
||||
* @return bool|null|string
|
||||
* @see recordLastTransactionID()
|
||||
*/
|
||||
public function getLastTransactionID()
|
||||
{
|
||||
return $this->last_smtp_transaction_id;
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
{
|
||||
"name": "phpmailer/phpmailer",
|
||||
"type": "library",
|
||||
"description": "PHPMailer is a full-featured email creation and transfer class for PHP",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Marcus Bointon",
|
||||
"email": "phpmailer@synchromedia.co.uk"
|
||||
},
|
||||
{
|
||||
"name": "Jim Jagielski",
|
||||
"email": "jimjag@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Andy Prevost",
|
||||
"email": "codeworxtech@users.sourceforge.net"
|
||||
},
|
||||
{
|
||||
"name": "Brent R. Matzelle"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"ext-ctype": "*",
|
||||
"php": ">=5.0.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/annotations": "1.2.*",
|
||||
"jms/serializer": "0.16.*",
|
||||
"phpdocumentor/phpdocumentor": "2.*",
|
||||
"phpunit/phpunit": "4.8.*",
|
||||
"symfony/debug": "2.8.*",
|
||||
"symfony/filesystem": "2.8.*",
|
||||
"symfony/translation": "2.8.*",
|
||||
"symfony/yaml": "2.8.*",
|
||||
"zendframework/zend-cache": "2.5.1",
|
||||
"zendframework/zend-config": "2.5.1",
|
||||
"zendframework/zend-eventmanager": "2.5.1",
|
||||
"zendframework/zend-filter": "2.5.1",
|
||||
"zendframework/zend-i18n": "2.5.1",
|
||||
"zendframework/zend-json": "2.5.1",
|
||||
"zendframework/zend-math": "2.5.1",
|
||||
"zendframework/zend-serializer": "2.5.*",
|
||||
"zendframework/zend-servicemanager": "2.5.*",
|
||||
"zendframework/zend-stdlib": "2.5.1"
|
||||
},
|
||||
"suggest": {
|
||||
"league/oauth2-google": "Needed for Google XOAUTH2 authentication"
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"class.phpmailer.php",
|
||||
"class.phpmaileroauth.php",
|
||||
"class.phpmaileroauthgoogle.php",
|
||||
"class.smtp.php",
|
||||
"class.pop3.php",
|
||||
"extras/EasyPeasyICS.php",
|
||||
"extras/ntlm_sasl_client.php"
|
||||
]
|
||||
},
|
||||
"license": "LGPL-2.1"
|
||||
}
|
||||
Generated
-3593
File diff suppressed because it is too large.
Load diff
@@ -1,162 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Get an OAuth2 token from Google.
|
||||
* * Install this script on your server so that it's accessible
|
||||
* as [https/http]://<yourdomain>/<folder>/get_oauth_token.php
|
||||
* e.g.: http://localhost/phpmail/get_oauth_token.php
|
||||
* * Ensure dependencies are installed with 'composer install'
|
||||
* * Set up an app in your Google developer console
|
||||
* * Set the script address as the app's redirect URL
|
||||
* If no refresh token is obtained when running this file, revoke access to your app
|
||||
* using link: https://accounts.google.com/b/0/IssuedAuthSubTokens and run the script again.
|
||||
* This script requires PHP 5.4 or later
|
||||
* PHP Version 5.4
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Client\Provider;
|
||||
|
||||
require 'vendor/autoload.php';
|
||||
|
||||
use League\OAuth2\Client\Provider\Exception\IdentityProviderException;
|
||||
use League\OAuth2\Client\Token\AccessToken;
|
||||
use League\OAuth2\Client\Tool\BearerAuthorizationTrait;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
session_start();
|
||||
|
||||
//If this automatic URL doesn't work, set it yourself manually
|
||||
$redirectUri = isset($_SERVER['HTTPS']) ? 'https://' : 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];
|
||||
//$redirectUri = 'http://localhost/phpmailer/get_oauth_token.php';
|
||||
|
||||
//These details obtained are by setting up app in Google developer console.
|
||||
$clientId = 'RANDOMCHARS-----duv1n2.apps.googleusercontent.com';
|
||||
$clientSecret = 'RANDOMCHARS-----lGyjPcRtvP';
|
||||
|
||||
class Google extends AbstractProvider
|
||||
{
|
||||
use BearerAuthorizationTrait;
|
||||
|
||||
const ACCESS_TOKEN_RESOURCE_OWNER_ID = 'id';
|
||||
|
||||
/**
|
||||
* @var string If set, this will be sent to google as the "access_type" parameter.
|
||||
* @link https://developers.google.com/accounts/docs/OAuth2WebServer#offline
|
||||
*/
|
||||
protected $accessType;
|
||||
|
||||
/**
|
||||
* @var string If set, this will be sent to google as the "hd" parameter.
|
||||
* @link https://developers.google.com/accounts/docs/OAuth2Login#hd-param
|
||||
*/
|
||||
protected $hostedDomain;
|
||||
|
||||
/**
|
||||
* @var string If set, this will be sent to google as the "scope" parameter.
|
||||
* @link https://developers.google.com/gmail/api/auth/scopes
|
||||
*/
|
||||
protected $scope;
|
||||
|
||||
public function getBaseAuthorizationUrl()
|
||||
{
|
||||
return 'https://accounts.google.com/o/oauth2/auth';
|
||||
}
|
||||
|
||||
public function getBaseAccessTokenUrl(array $params)
|
||||
{
|
||||
return 'https://accounts.google.com/o/oauth2/token';
|
||||
}
|
||||
|
||||
public function getResourceOwnerDetailsUrl(AccessToken $token)
|
||||
{
|
||||
return ' ';
|
||||
}
|
||||
|
||||
protected function getAuthorizationParameters(array $options)
|
||||
{
|
||||
if (is_array($this->scope)) {
|
||||
$separator = $this->getScopeSeparator();
|
||||
$this->scope = implode($separator, $this->scope);
|
||||
}
|
||||
|
||||
$params = array_merge(
|
||||
parent::getAuthorizationParameters($options),
|
||||
array_filter([
|
||||
'hd' => $this->hostedDomain,
|
||||
'access_type' => $this->accessType,
|
||||
'scope' => $this->scope,
|
||||
// if the user is logged in with more than one account ask which one to use for the login!
|
||||
'authuser' => '-1'
|
||||
])
|
||||
);
|
||||
return $params;
|
||||
}
|
||||
|
||||
protected function getDefaultScopes()
|
||||
{
|
||||
return [
|
||||
'email',
|
||||
'openid',
|
||||
'profile',
|
||||
];
|
||||
}
|
||||
|
||||
protected function getScopeSeparator()
|
||||
{
|
||||
return ' ';
|
||||
}
|
||||
|
||||
protected function checkResponse(ResponseInterface $response, $data)
|
||||
{
|
||||
if (!empty($data['error'])) {
|
||||
$code = 0;
|
||||
$error = $data['error'];
|
||||
|
||||
if (is_array($error)) {
|
||||
$code = $error['code'];
|
||||
$error = $error['message'];
|
||||
}
|
||||
|
||||
throw new IdentityProviderException($error, $code, $data);
|
||||
}
|
||||
}
|
||||
|
||||
protected function createResourceOwner(array $response, AccessToken $token)
|
||||
{
|
||||
return new GoogleUser($response);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Set Redirect URI in Developer Console as [https/http]://<yourdomain>/<folder>/get_oauth_token.php
|
||||
$provider = new Google(
|
||||
array(
|
||||
'clientId' => $clientId,
|
||||
'clientSecret' => $clientSecret,
|
||||
'redirectUri' => $redirectUri,
|
||||
'scope' => array('https://mail.google.com/'),
|
||||
'accessType' => 'offline'
|
||||
)
|
||||
);
|
||||
|
||||
if (!isset($_GET['code'])) {
|
||||
// If we don't have an authorization code then get one
|
||||
$authUrl = $provider->getAuthorizationUrl();
|
||||
$_SESSION['oauth2state'] = $provider->getState();
|
||||
header('Location: ' . $authUrl);
|
||||
exit;
|
||||
// Check given state against previously stored one to mitigate CSRF attack
|
||||
} elseif (empty($_GET['state']) || ($_GET['state'] !== $_SESSION['oauth2state'])) {
|
||||
unset($_SESSION['oauth2state']);
|
||||
exit('Invalid state');
|
||||
} else {
|
||||
// Try to get an access token (using the authorization code grant)
|
||||
$token = $provider->getAccessToken(
|
||||
'authorization_code',
|
||||
array(
|
||||
'code' => $_GET['code']
|
||||
)
|
||||
);
|
||||
|
||||
// Use this to get a new access token if the old one expires
|
||||
echo 'Refresh Token: ' . $token->getRefreshToken();
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
<?php
|
||||
|
||||
include(__DIR__.'/plates/Engine.php');
|
||||
include(__DIR__.'/plates/Extension/ExtensionInterface.php');
|
||||
include(__DIR__.'/plates/Template/Data.php');
|
||||
include(__DIR__.'/plates/Template/Directory.php');
|
||||
include(__DIR__.'/plates/Template/FileExtension.php');
|
||||
include(__DIR__.'/plates/Template/Folders.php');
|
||||
include(__DIR__.'/plates/Template/Func.php');
|
||||
include(__DIR__.'/plates/Template/Functions.php');
|
||||
include(__DIR__.'/plates/Template/Name.php');
|
||||
include(__DIR__.'/plates/Template/Template.php');
|
||||
|
||||
class Plates extends League\Plates\Engine { }
|
||||
|
||||
?>
|
||||
@@ -1,279 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace League\Plates;
|
||||
|
||||
use League\Plates\Extension\ExtensionInterface;
|
||||
use League\Plates\Template\Data;
|
||||
use League\Plates\Template\Directory;
|
||||
use League\Plates\Template\FileExtension;
|
||||
use League\Plates\Template\Folders;
|
||||
use League\Plates\Template\Func;
|
||||
use League\Plates\Template\Functions;
|
||||
use League\Plates\Template\Name;
|
||||
use League\Plates\Template\Template;
|
||||
|
||||
/**
|
||||
* Template API and environment settings storage.
|
||||
*/
|
||||
class Engine
|
||||
{
|
||||
/**
|
||||
* Default template directory.
|
||||
* @var Directory
|
||||
*/
|
||||
protected $directory;
|
||||
|
||||
/**
|
||||
* Template file extension.
|
||||
* @var FileExtension
|
||||
*/
|
||||
protected $fileExtension;
|
||||
|
||||
/**
|
||||
* Collection of template folders.
|
||||
* @var Folders
|
||||
*/
|
||||
protected $folders;
|
||||
|
||||
/**
|
||||
* Collection of template functions.
|
||||
* @var Functions
|
||||
*/
|
||||
protected $functions;
|
||||
|
||||
/**
|
||||
* Collection of preassigned template data.
|
||||
* @var Data
|
||||
*/
|
||||
protected $data;
|
||||
|
||||
/**
|
||||
* Create new Engine instance.
|
||||
* @param string $directory
|
||||
* @param string $fileExtension
|
||||
*/
|
||||
public function __construct($directory = null, $fileExtension = 'php')
|
||||
{
|
||||
$this->directory = new Directory($directory);
|
||||
$this->fileExtension = new FileExtension($fileExtension);
|
||||
$this->folders = new Folders();
|
||||
$this->functions = new Functions();
|
||||
$this->data = new Data();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set path to templates directory.
|
||||
* @param string|null $directory Pass null to disable the default directory.
|
||||
* @return Engine
|
||||
*/
|
||||
public function setDirectory($directory)
|
||||
{
|
||||
$this->directory->set($directory);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get path to templates directory.
|
||||
* @return string
|
||||
*/
|
||||
public function getDirectory()
|
||||
{
|
||||
return $this->directory->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the template file extension.
|
||||
* @param string|null $fileExtension Pass null to manually set it.
|
||||
* @return Engine
|
||||
*/
|
||||
public function setFileExtension($fileExtension)
|
||||
{
|
||||
$this->fileExtension->set($fileExtension);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the template file extension.
|
||||
* @return string
|
||||
*/
|
||||
public function getFileExtension()
|
||||
{
|
||||
return $this->fileExtension->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new template folder for grouping templates under different namespaces.
|
||||
* @param string $name
|
||||
* @param string $directory
|
||||
* @param boolean $fallback
|
||||
* @return Engine
|
||||
*/
|
||||
public function addFolder($name, $directory, $fallback = false)
|
||||
{
|
||||
$this->folders->add($name, $directory, $fallback);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a template folder.
|
||||
* @param string $name
|
||||
* @return Engine
|
||||
*/
|
||||
public function removeFolder($name)
|
||||
{
|
||||
$this->folders->remove($name);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get collection of all template folders.
|
||||
* @return Folders
|
||||
*/
|
||||
public function getFolders()
|
||||
{
|
||||
return $this->folders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add preassigned template data.
|
||||
* @param array $data;
|
||||
* @param null|string|array $templates;
|
||||
* @return Engine
|
||||
*/
|
||||
public function addData(array $data, $templates = null)
|
||||
{
|
||||
$this->data->add($data, $templates);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all preassigned template data.
|
||||
* @param null|string $template;
|
||||
* @return array
|
||||
*/
|
||||
public function getData($template = null)
|
||||
{
|
||||
return $this->data->get($template);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a new template function.
|
||||
* @param string $name;
|
||||
* @param callback $callback;
|
||||
* @return Engine
|
||||
*/
|
||||
public function registerFunction($name, $callback)
|
||||
{
|
||||
$this->functions->add($name, $callback);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a template function.
|
||||
* @param string $name;
|
||||
* @return Engine
|
||||
*/
|
||||
public function dropFunction($name)
|
||||
{
|
||||
$this->functions->remove($name);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a template function.
|
||||
* @param string $name
|
||||
* @return Func
|
||||
*/
|
||||
public function getFunction($name)
|
||||
{
|
||||
return $this->functions->get($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a template function exists.
|
||||
* @param string $name
|
||||
* @return boolean
|
||||
*/
|
||||
public function doesFunctionExist($name)
|
||||
{
|
||||
return $this->functions->exists($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load an extension.
|
||||
* @param ExtensionInterface $extension
|
||||
* @return Engine
|
||||
*/
|
||||
public function loadExtension(ExtensionInterface $extension)
|
||||
{
|
||||
$extension->register($this);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load multiple extensions.
|
||||
* @param array $extensions
|
||||
* @return Engine
|
||||
*/
|
||||
public function loadExtensions(array $extensions = array())
|
||||
{
|
||||
foreach ($extensions as $extension) {
|
||||
$this->loadExtension($extension);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a template path.
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
public function path($name)
|
||||
{
|
||||
$name = new Name($this, $name);
|
||||
|
||||
return $name->getPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a template exists.
|
||||
* @param string $name
|
||||
* @return boolean
|
||||
*/
|
||||
public function exists($name)
|
||||
{
|
||||
$name = new Name($this, $name);
|
||||
|
||||
return $name->doesPathExist();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new template.
|
||||
* @param string $name
|
||||
* @return Template
|
||||
*/
|
||||
public function make($name)
|
||||
{
|
||||
return new Template($this, $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new template and render it.
|
||||
* @param string $name
|
||||
* @param array $data
|
||||
* @return string
|
||||
*/
|
||||
public function render($name, array $data = array())
|
||||
{
|
||||
return $this->make($name)->render($data);
|
||||
}
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace League\Plates\Extension;
|
||||
|
||||
use League\Plates\Engine;
|
||||
use League\Plates\Template\Template;
|
||||
use LogicException;
|
||||
|
||||
/**
|
||||
* Extension that adds the ability to create "cache busted" asset URLs.
|
||||
*/
|
||||
class Asset implements ExtensionInterface
|
||||
{
|
||||
/**
|
||||
* Instance of the current template.
|
||||
* @var Template
|
||||
*/
|
||||
public $template;
|
||||
|
||||
/**
|
||||
* Path to asset directory.
|
||||
* @var string
|
||||
*/
|
||||
public $path;
|
||||
|
||||
/**
|
||||
* Enables the filename method.
|
||||
* @var boolean
|
||||
*/
|
||||
public $filenameMethod;
|
||||
|
||||
/**
|
||||
* Create new Asset instance.
|
||||
* @param string $path
|
||||
* @param boolean $filenameMethod
|
||||
*/
|
||||
public function __construct($path, $filenameMethod = false)
|
||||
{
|
||||
$this->path = rtrim($path, '/');
|
||||
$this->filenameMethod = $filenameMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register extension function.
|
||||
* @param Engine $engine
|
||||
* @return null
|
||||
*/
|
||||
public function register(Engine $engine)
|
||||
{
|
||||
$engine->registerFunction('asset', array($this, 'cachedAssetUrl'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create "cache busted" asset URL.
|
||||
* @param string $url
|
||||
* @return string
|
||||
*/
|
||||
public function cachedAssetUrl($url)
|
||||
{
|
||||
$filePath = $this->path . '/' . ltrim($url, '/');
|
||||
|
||||
if (!file_exists($filePath)) {
|
||||
throw new LogicException(
|
||||
'Unable to locate the asset "' . $url . '" in the "' . $this->path . '" directory.'
|
||||
);
|
||||
}
|
||||
|
||||
$lastUpdated = filemtime($filePath);
|
||||
$pathInfo = pathinfo($url);
|
||||
|
||||
if ($pathInfo['dirname'] === '.') {
|
||||
$directory = '';
|
||||
} elseif ($pathInfo['dirname'] === '/') {
|
||||
$directory = '/';
|
||||
} else {
|
||||
$directory = $pathInfo['dirname'] . '/';
|
||||
}
|
||||
|
||||
if ($this->filenameMethod) {
|
||||
return $directory . $pathInfo['filename'] . '.' . $lastUpdated . '.' . $pathInfo['extension'];
|
||||
}
|
||||
|
||||
return $directory . $pathInfo['filename'] . '.' . $pathInfo['extension'] . '?v=' . $lastUpdated;
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace League\Plates\Extension;
|
||||
|
||||
use League\Plates\Engine;
|
||||
|
||||
/**
|
||||
* A common interface for extensions.
|
||||
*/
|
||||
interface ExtensionInterface
|
||||
{
|
||||
public function register(Engine $engine);
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace League\Plates\Extension;
|
||||
|
||||
use League\Plates\Engine;
|
||||
use League\Plates\Template\Template;
|
||||
use LogicException;
|
||||
|
||||
/**
|
||||
* Extension that adds a number of URI checks.
|
||||
*/
|
||||
class URI implements ExtensionInterface
|
||||
{
|
||||
/**
|
||||
* Instance of the current template.
|
||||
* @var Template
|
||||
*/
|
||||
public $template;
|
||||
|
||||
/**
|
||||
* The request URI.
|
||||
* @var string
|
||||
*/
|
||||
protected $uri;
|
||||
|
||||
/**
|
||||
* The request URI as an array.
|
||||
* @var array
|
||||
*/
|
||||
protected $parts;
|
||||
|
||||
/**
|
||||
* Create new URI instance.
|
||||
* @param string $uri
|
||||
*/
|
||||
public function __construct($uri)
|
||||
{
|
||||
$this->uri = $uri;
|
||||
$this->parts = explode('/', $this->uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register extension functions.
|
||||
* @param Engine $engine
|
||||
* @return null
|
||||
*/
|
||||
public function register(Engine $engine)
|
||||
{
|
||||
$engine->registerFunction('uri', array($this, 'runUri'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform URI check.
|
||||
* @param null|integer|string $var1
|
||||
* @param mixed $var2
|
||||
* @param mixed $var3
|
||||
* @param mixed $var4
|
||||
* @return mixed
|
||||
*/
|
||||
public function runUri($var1 = null, $var2 = null, $var3 = null, $var4 = null)
|
||||
{
|
||||
if (is_null($var1)) {
|
||||
return $this->uri;
|
||||
}
|
||||
|
||||
if (is_numeric($var1) and is_null($var2)) {
|
||||
return array_key_exists($var1, $this->parts) ? $this->parts[$var1] : null;
|
||||
}
|
||||
|
||||
if (is_numeric($var1) and is_string($var2)) {
|
||||
return $this->checkUriSegmentMatch($var1, $var2, $var3, $var4);
|
||||
}
|
||||
|
||||
if (is_string($var1)) {
|
||||
return $this->checkUriRegexMatch($var1, $var2, $var3);
|
||||
}
|
||||
|
||||
throw new LogicException('Invalid use of the uri function.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a URI segment match.
|
||||
* @param integer $key
|
||||
* @param string $string
|
||||
* @param mixed $returnOnTrue
|
||||
* @param mixed $returnOnFalse
|
||||
* @return mixed
|
||||
*/
|
||||
protected function checkUriSegmentMatch($key, $string, $returnOnTrue = null, $returnOnFalse = null)
|
||||
{
|
||||
if (array_key_exists($key, $this->parts) && $this->parts[$key] === $string) {
|
||||
return is_null($returnOnTrue) ? true : $returnOnTrue;
|
||||
}
|
||||
|
||||
return is_null($returnOnFalse) ? false : $returnOnFalse;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a regular express match.
|
||||
* @param string $regex
|
||||
* @param mixed $returnOnTrue
|
||||
* @param mixed $returnOnFalse
|
||||
* @return mixed
|
||||
*/
|
||||
protected function checkUriRegexMatch($regex, $returnOnTrue = null, $returnOnFalse = null)
|
||||
{
|
||||
if (preg_match('#^' . $regex . '$#', $this->uri) === 1) {
|
||||
return is_null($returnOnTrue) ? true : $returnOnTrue;
|
||||
}
|
||||
|
||||
return is_null($returnOnFalse) ? false : $returnOnFalse;
|
||||
}
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace League\Plates\Template;
|
||||
|
||||
use LogicException;
|
||||
|
||||
/**
|
||||
* Preassigned template data.
|
||||
*/
|
||||
class Data
|
||||
{
|
||||
/**
|
||||
* Variables shared by all templates.
|
||||
* @var array
|
||||
*/
|
||||
protected $sharedVariables = array();
|
||||
|
||||
/**
|
||||
* Specific template variables.
|
||||
* @var array
|
||||
*/
|
||||
protected $templateVariables = array();
|
||||
|
||||
/**
|
||||
* Add template data.
|
||||
* @param array $data;
|
||||
* @param null|string|array $templates;
|
||||
* @return Data
|
||||
*/
|
||||
public function add(array $data, $templates = null)
|
||||
{
|
||||
if (is_null($templates)) {
|
||||
return $this->shareWithAll($data);
|
||||
}
|
||||
|
||||
if (is_array($templates)) {
|
||||
return $this->shareWithSome($data, $templates);
|
||||
}
|
||||
|
||||
if (is_string($templates)) {
|
||||
return $this->shareWithSome($data, array($templates));
|
||||
}
|
||||
|
||||
throw new LogicException(
|
||||
'The templates variable must be null, an array or a string, ' . gettype($templates) . ' given.'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add data shared with all templates.
|
||||
* @param array $data;
|
||||
* @return Data
|
||||
*/
|
||||
public function shareWithAll($data)
|
||||
{
|
||||
$this->sharedVariables = array_merge($this->sharedVariables, $data);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add data shared with some templates.
|
||||
* @param array $data;
|
||||
* @param array $templates;
|
||||
* @return Data
|
||||
*/
|
||||
public function shareWithSome($data, array $templates)
|
||||
{
|
||||
foreach ($templates as $template) {
|
||||
if (isset($this->templateVariables[$template])) {
|
||||
$this->templateVariables[$template] = array_merge($this->templateVariables[$template], $data);
|
||||
} else {
|
||||
$this->templateVariables[$template] = $data;
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get template data.
|
||||
* @param null|string $template;
|
||||
* @return array
|
||||
*/
|
||||
public function get($template = null)
|
||||
{
|
||||
if (isset($template, $this->templateVariables[$template])) {
|
||||
return array_merge($this->sharedVariables, $this->templateVariables[$template]);
|
||||
}
|
||||
|
||||
return $this->sharedVariables;
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace League\Plates\Template;
|
||||
|
||||
use LogicException;
|
||||
|
||||
/**
|
||||
* Default template directory.
|
||||
*/
|
||||
class Directory
|
||||
{
|
||||
/**
|
||||
* Template directory path.
|
||||
* @var string
|
||||
*/
|
||||
protected $path;
|
||||
|
||||
/**
|
||||
* Create new Directory instance.
|
||||
* @param string $path
|
||||
*/
|
||||
public function __construct($path = null)
|
||||
{
|
||||
$this->set($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set path to templates directory.
|
||||
* @param string|null $path Pass null to disable the default directory.
|
||||
* @return Directory
|
||||
*/
|
||||
public function set($path)
|
||||
{
|
||||
if (!is_null($path) and !is_dir($path)) {
|
||||
throw new LogicException(
|
||||
'The specified path "' . $path . '" does not exist.'
|
||||
);
|
||||
}
|
||||
|
||||
$this->path = $path;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get path to templates directory.
|
||||
* @return string
|
||||
*/
|
||||
public function get()
|
||||
{
|
||||
return $this->path;
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace League\Plates\Template;
|
||||
|
||||
/**
|
||||
* Template file extension.
|
||||
*/
|
||||
class FileExtension
|
||||
{
|
||||
/**
|
||||
* Template file extension.
|
||||
* @var string
|
||||
*/
|
||||
protected $fileExtension;
|
||||
|
||||
/**
|
||||
* Create new FileExtension instance.
|
||||
* @param null|string $fileExtension
|
||||
*/
|
||||
public function __construct($fileExtension = 'php')
|
||||
{
|
||||
$this->set($fileExtension);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the template file extension.
|
||||
* @param null|string $fileExtension
|
||||
* @return FileExtension
|
||||
*/
|
||||
public function set($fileExtension)
|
||||
{
|
||||
$this->fileExtension = $fileExtension;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the template file extension.
|
||||
* @return string
|
||||
*/
|
||||
public function get()
|
||||
{
|
||||
return $this->fileExtension;
|
||||
}
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace League\Plates\Template;
|
||||
|
||||
use LogicException;
|
||||
|
||||
/**
|
||||
* A template folder.
|
||||
*/
|
||||
class Folder
|
||||
{
|
||||
/**
|
||||
* The folder name.
|
||||
* @var string
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* The folder path.
|
||||
* @var string
|
||||
*/
|
||||
protected $path;
|
||||
|
||||
/**
|
||||
* The folder fallback status.
|
||||
* @var boolean
|
||||
*/
|
||||
protected $fallback;
|
||||
|
||||
/**
|
||||
* Create a new Folder instance.
|
||||
* @param string $name
|
||||
* @param string $path
|
||||
* @param boolean $fallback
|
||||
*/
|
||||
public function __construct($name, $path, $fallback = false)
|
||||
{
|
||||
$this->setName($name);
|
||||
$this->setPath($path);
|
||||
$this->setFallback($fallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the folder name.
|
||||
* @param string $name
|
||||
* @return Folder
|
||||
*/
|
||||
public function setName($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the folder name.
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the folder path.
|
||||
* @param string $path
|
||||
* @return Folder
|
||||
*/
|
||||
public function setPath($path)
|
||||
{
|
||||
if (!is_dir($path)) {
|
||||
throw new LogicException('The specified directory path "' . $path . '" does not exist.');
|
||||
}
|
||||
|
||||
$this->path = $path;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the folder path.
|
||||
* @return string
|
||||
*/
|
||||
public function getPath()
|
||||
{
|
||||
return $this->path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the folder fallback status.
|
||||
* @param boolean $fallback
|
||||
* @return Folder
|
||||
*/
|
||||
public function setFallback($fallback)
|
||||
{
|
||||
$this->fallback = $fallback;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the folder fallback status.
|
||||
* @return boolean
|
||||
*/
|
||||
public function getFallback()
|
||||
{
|
||||
return $this->fallback;
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace League\Plates\Template;
|
||||
|
||||
use LogicException;
|
||||
|
||||
/**
|
||||
* A collection of template folders.
|
||||
*/
|
||||
class Folders
|
||||
{
|
||||
/**
|
||||
* Array of template folders.
|
||||
* @var array
|
||||
*/
|
||||
protected $folders = array();
|
||||
|
||||
/**
|
||||
* Add a template folder.
|
||||
* @param string $name
|
||||
* @param string $path
|
||||
* @param boolean $fallback
|
||||
* @return Folders
|
||||
*/
|
||||
public function add($name, $path, $fallback = false)
|
||||
{
|
||||
if ($this->exists($name)) {
|
||||
throw new LogicException('The template folder "' . $name . '" is already being used.');
|
||||
}
|
||||
|
||||
$this->folders[$name] = new Folder($name, $path, $fallback);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a template folder.
|
||||
* @param string $name
|
||||
* @return Folders
|
||||
*/
|
||||
public function remove($name)
|
||||
{
|
||||
if (!$this->exists($name)) {
|
||||
throw new LogicException('The template folder "' . $name . '" was not found.');
|
||||
}
|
||||
|
||||
unset($this->folders[$name]);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a template folder.
|
||||
* @param string $name
|
||||
* @return Folder
|
||||
*/
|
||||
public function get($name)
|
||||
{
|
||||
if (!$this->exists($name)) {
|
||||
throw new LogicException('The template folder "' . $name . '" was not found.');
|
||||
}
|
||||
|
||||
return $this->folders[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a template folder exists.
|
||||
* @param string $name
|
||||
* @return boolean
|
||||
*/
|
||||
public function exists($name)
|
||||
{
|
||||
return isset($this->folders[$name]);
|
||||
}
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace League\Plates\Template;
|
||||
|
||||
use League\Plates\Extension\ExtensionInterface;
|
||||
use LogicException;
|
||||
|
||||
/**
|
||||
* A template function.
|
||||
*/
|
||||
class Func
|
||||
{
|
||||
/**
|
||||
* The function name.
|
||||
* @var string
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* The function callback.
|
||||
* @var callable
|
||||
*/
|
||||
protected $callback;
|
||||
|
||||
/**
|
||||
* Create new Func instance.
|
||||
* @param string $name
|
||||
* @param callable $callback
|
||||
*/
|
||||
public function __construct($name, $callback)
|
||||
{
|
||||
$this->setName($name);
|
||||
$this->setCallback($callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the function name.
|
||||
* @param string $name
|
||||
* @return Func
|
||||
*/
|
||||
public function setName($name)
|
||||
{
|
||||
if (preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $name) !== 1) {
|
||||
throw new LogicException(
|
||||
'Not a valid function name.'
|
||||
);
|
||||
}
|
||||
|
||||
$this->name = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the function name.
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the function callback
|
||||
* @param callable $callback
|
||||
* @return Func
|
||||
*/
|
||||
public function setCallback($callback)
|
||||
{
|
||||
if (!is_callable($callback, true)) {
|
||||
throw new LogicException(
|
||||
'Not a valid function callback.'
|
||||
);
|
||||
}
|
||||
|
||||
$this->callback = $callback;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the function callback.
|
||||
* @return callable
|
||||
*/
|
||||
public function getCallback()
|
||||
{
|
||||
return $this->callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the function.
|
||||
* @param Template $template
|
||||
* @param array $arguments
|
||||
* @return mixed
|
||||
*/
|
||||
public function call(Template $template = null, $arguments = array())
|
||||
{
|
||||
if (is_array($this->callback) and
|
||||
isset($this->callback[0]) and
|
||||
$this->callback[0] instanceof ExtensionInterface
|
||||
) {
|
||||
$this->callback[0]->template = $template;
|
||||
}
|
||||
|
||||
return call_user_func_array($this->callback, $arguments);
|
||||
}
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace League\Plates\Template;
|
||||
|
||||
use LogicException;
|
||||
|
||||
/**
|
||||
* A collection of template functions.
|
||||
*/
|
||||
class Functions
|
||||
{
|
||||
/**
|
||||
* Array of template functions.
|
||||
* @var array
|
||||
*/
|
||||
protected $functions = array();
|
||||
|
||||
/**
|
||||
* Add a new template function.
|
||||
* @param string $name;
|
||||
* @param callback $callback;
|
||||
* @return Functions
|
||||
*/
|
||||
public function add($name, $callback)
|
||||
{
|
||||
if ($this->exists($name)) {
|
||||
throw new LogicException(
|
||||
'The template function name "' . $name . '" is already registered.'
|
||||
);
|
||||
}
|
||||
|
||||
$this->functions[$name] = new Func($name, $callback);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a template function.
|
||||
* @param string $name;
|
||||
* @return Functions
|
||||
*/
|
||||
public function remove($name)
|
||||
{
|
||||
if (!$this->exists($name)) {
|
||||
throw new LogicException(
|
||||
'The template function "' . $name . '" was not found.'
|
||||
);
|
||||
}
|
||||
|
||||
unset($this->functions[$name]);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a template function.
|
||||
* @param string $name
|
||||
* @return Func
|
||||
*/
|
||||
public function get($name)
|
||||
{
|
||||
if (!$this->exists($name)) {
|
||||
throw new LogicException('The template function "' . $name . '" was not found.');
|
||||
}
|
||||
|
||||
return $this->functions[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a template function exists.
|
||||
* @param string $name
|
||||
* @return boolean
|
||||
*/
|
||||
public function exists($name)
|
||||
{
|
||||
return isset($this->functions[$name]);
|
||||
}
|
||||
}
|
||||
@@ -1,202 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace League\Plates\Template;
|
||||
|
||||
use League\Plates\Engine;
|
||||
use LogicException;
|
||||
|
||||
/**
|
||||
* A template name.
|
||||
*/
|
||||
class Name
|
||||
{
|
||||
/**
|
||||
* Instance of the template engine.
|
||||
* @var Engine
|
||||
*/
|
||||
protected $engine;
|
||||
|
||||
/**
|
||||
* The original name.
|
||||
* @var string
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* The parsed template folder.
|
||||
* @var Folder
|
||||
*/
|
||||
protected $folder;
|
||||
|
||||
/**
|
||||
* The parsed template filename.
|
||||
* @var string
|
||||
*/
|
||||
protected $file;
|
||||
|
||||
/**
|
||||
* Create a new Name instance.
|
||||
* @param Engine $engine
|
||||
* @param string $name
|
||||
*/
|
||||
public function __construct(Engine $engine, $name)
|
||||
{
|
||||
$this->setEngine($engine);
|
||||
$this->setName($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the engine.
|
||||
* @param Engine $engine
|
||||
* @return Name
|
||||
*/
|
||||
public function setEngine(Engine $engine)
|
||||
{
|
||||
$this->engine = $engine;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the engine.
|
||||
* @return Engine
|
||||
*/
|
||||
public function getEngine()
|
||||
{
|
||||
return $this->engine;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the original name and parse it.
|
||||
* @param string $name
|
||||
* @return Name
|
||||
*/
|
||||
public function setName($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
|
||||
$parts = explode('::', $this->name);
|
||||
|
||||
if (count($parts) === 1) {
|
||||
$this->setFile($parts[0]);
|
||||
} elseif (count($parts) === 2) {
|
||||
$this->setFolder($parts[0]);
|
||||
$this->setFile($parts[1]);
|
||||
} else {
|
||||
throw new LogicException(
|
||||
'The template name "' . $this->name . '" is not valid. ' .
|
||||
'Do not use the folder namespace separator "::" more than once.'
|
||||
);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the original name.
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the parsed template folder.
|
||||
* @param string $folder
|
||||
* @return Name
|
||||
*/
|
||||
public function setFolder($folder)
|
||||
{
|
||||
$this->folder = $this->engine->getFolders()->get($folder);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the parsed template folder.
|
||||
* @return string
|
||||
*/
|
||||
public function getFolder()
|
||||
{
|
||||
return $this->folder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the parsed template file.
|
||||
* @param string $file
|
||||
* @return Name
|
||||
*/
|
||||
public function setFile($file)
|
||||
{
|
||||
if ($file === '') {
|
||||
throw new LogicException(
|
||||
'The template name "' . $this->name . '" is not valid. ' .
|
||||
'The template name cannot be empty.'
|
||||
);
|
||||
}
|
||||
|
||||
$this->file = $file;
|
||||
|
||||
if (!is_null($this->engine->getFileExtension())) {
|
||||
$this->file .= '.' . $this->engine->getFileExtension();
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the parsed template file.
|
||||
* @return string
|
||||
*/
|
||||
public function getFile()
|
||||
{
|
||||
return $this->file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve template path.
|
||||
* @return string
|
||||
*/
|
||||
public function getPath()
|
||||
{
|
||||
if (is_null($this->folder)) {
|
||||
return $this->getDefaultDirectory() . DIRECTORY_SEPARATOR . $this->file;
|
||||
}
|
||||
|
||||
$path = $this->folder->getPath() . DIRECTORY_SEPARATOR . $this->file;
|
||||
|
||||
if (!is_file($path) and $this->folder->getFallback() and is_file($this->getDefaultDirectory() . DIRECTORY_SEPARATOR . $this->file)) {
|
||||
$path = $this->getDefaultDirectory() . DIRECTORY_SEPARATOR . $this->file;
|
||||
}
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if template path exists.
|
||||
* @return boolean
|
||||
*/
|
||||
public function doesPathExist()
|
||||
{
|
||||
return is_file($this->getPath());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default templates directory.
|
||||
* @return string
|
||||
*/
|
||||
protected function getDefaultDirectory()
|
||||
{
|
||||
$directory = $this->engine->getDirectory();
|
||||
|
||||
if (is_null($directory)) {
|
||||
throw new LogicException(
|
||||
'The template name "' . $this->name . '" is not valid. '.
|
||||
'The default directory has not been defined.'
|
||||
);
|
||||
}
|
||||
|
||||
return $directory;
|
||||
}
|
||||
}
|
||||
@@ -1,346 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace League\Plates\Template;
|
||||
|
||||
use Exception;
|
||||
use League\Plates\Engine;
|
||||
use LogicException;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Container which holds template data and provides access to template functions.
|
||||
*/
|
||||
class Template
|
||||
{
|
||||
/**
|
||||
* Instance of the template engine.
|
||||
* @var Engine
|
||||
*/
|
||||
protected $engine;
|
||||
|
||||
/**
|
||||
* The name of the template.
|
||||
* @var Name
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* The data assigned to the template.
|
||||
* @var array
|
||||
*/
|
||||
protected $data = array();
|
||||
|
||||
/**
|
||||
* An array of section content.
|
||||
* @var array
|
||||
*/
|
||||
protected $sections = array();
|
||||
|
||||
/**
|
||||
* The name of the section currently being rendered.
|
||||
* @var string
|
||||
*/
|
||||
protected $sectionName;
|
||||
|
||||
/**
|
||||
* Whether the section should be appended or not.
|
||||
* @var boolean
|
||||
*/
|
||||
protected $appendSection;
|
||||
|
||||
/**
|
||||
* The name of the template layout.
|
||||
* @var string
|
||||
*/
|
||||
protected $layoutName;
|
||||
|
||||
/**
|
||||
* The data assigned to the template layout.
|
||||
* @var array
|
||||
*/
|
||||
protected $layoutData;
|
||||
|
||||
/**
|
||||
* Create new Template instance.
|
||||
* @param Engine $engine
|
||||
* @param string $name
|
||||
*/
|
||||
public function __construct(Engine $engine, $name)
|
||||
{
|
||||
$this->engine = $engine;
|
||||
$this->name = new Name($engine, $name);
|
||||
|
||||
$this->data($this->engine->getData($name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic method used to call extension functions.
|
||||
* @param string $name
|
||||
* @param array $arguments
|
||||
* @return mixed
|
||||
*/
|
||||
public function __call($name, $arguments)
|
||||
{
|
||||
return $this->engine->getFunction($name)->call($this, $arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias for render() method.
|
||||
* @throws \Throwable
|
||||
* @throws \Exception
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign or get template data.
|
||||
* @param array $data
|
||||
* @return mixed
|
||||
*/
|
||||
public function data(array $data = null)
|
||||
{
|
||||
if (is_null($data)) {
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
$this->data = array_merge($this->data, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the template exists.
|
||||
* @return boolean
|
||||
*/
|
||||
public function exists()
|
||||
{
|
||||
return $this->name->doesPathExist();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the template path.
|
||||
* @return string
|
||||
*/
|
||||
public function path()
|
||||
{
|
||||
return $this->name->getPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the template and layout.
|
||||
* @param array $data
|
||||
* @throws \Throwable
|
||||
* @throws \Exception
|
||||
* @return string
|
||||
*/
|
||||
public function render(array $data = array())
|
||||
{
|
||||
$this->data($data);
|
||||
unset($data);
|
||||
extract($this->data);
|
||||
|
||||
if (!$this->exists()) {
|
||||
throw new LogicException(
|
||||
'The template "' . $this->name->getName() . '" could not be found at "' . $this->path() . '".'
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
$level = ob_get_level();
|
||||
ob_start();
|
||||
|
||||
include $this->path();
|
||||
|
||||
$content = ob_get_clean();
|
||||
|
||||
if (isset($this->layoutName)) {
|
||||
$layout = $this->engine->make($this->layoutName);
|
||||
$layout->sections = array_merge($this->sections, array('content' => $content));
|
||||
$content = $layout->render($this->layoutData);
|
||||
}
|
||||
|
||||
return $content;
|
||||
} catch (Throwable $e) {
|
||||
while (ob_get_level() > $level) {
|
||||
ob_end_clean();
|
||||
}
|
||||
|
||||
throw $e;
|
||||
} catch (Exception $e) {
|
||||
while (ob_get_level() > $level) {
|
||||
ob_end_clean();
|
||||
}
|
||||
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the template's layout.
|
||||
* @param string $name
|
||||
* @param array $data
|
||||
* @return null
|
||||
*/
|
||||
public function layout($name, array $data = array())
|
||||
{
|
||||
$this->layoutName = $name;
|
||||
$this->layoutData = $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a new section block.
|
||||
* @param string $name
|
||||
* @return null
|
||||
*/
|
||||
public function start($name)
|
||||
{
|
||||
if ($name === 'content') {
|
||||
throw new LogicException(
|
||||
'The section name "content" is reserved.'
|
||||
);
|
||||
}
|
||||
|
||||
if ($this->sectionName) {
|
||||
throw new LogicException('You cannot nest sections within other sections.');
|
||||
}
|
||||
|
||||
$this->sectionName = $name;
|
||||
|
||||
ob_start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a new append section block.
|
||||
* @param string $name
|
||||
* @return null
|
||||
*/
|
||||
public function push($name)
|
||||
{
|
||||
$this->appendSection = true;
|
||||
|
||||
$this->start($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the current section block.
|
||||
* @return null
|
||||
*/
|
||||
public function stop()
|
||||
{
|
||||
if (is_null($this->sectionName)) {
|
||||
throw new LogicException(
|
||||
'You must start a section before you can stop it.'
|
||||
);
|
||||
}
|
||||
|
||||
if (!isset($this->sections[$this->sectionName])) {
|
||||
$this->sections[$this->sectionName] = '';
|
||||
}
|
||||
|
||||
$this->sections[$this->sectionName] = $this->appendSection ? $this->sections[$this->sectionName] . ob_get_clean() : ob_get_clean();
|
||||
$this->sectionName = null;
|
||||
$this->appendSection = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias of stop().
|
||||
* @return null
|
||||
*/
|
||||
public function end()
|
||||
{
|
||||
$this->stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the content for a section block.
|
||||
* @param string $name Section name
|
||||
* @param string $default Default section content
|
||||
* @return string|null
|
||||
*/
|
||||
public function section($name, $default = null)
|
||||
{
|
||||
if (!isset($this->sections[$name])) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
return $this->sections[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch a rendered template.
|
||||
* @param string $name
|
||||
* @param array $data
|
||||
* @return string
|
||||
*/
|
||||
public function fetch($name, array $data = array())
|
||||
{
|
||||
return $this->engine->render($name, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Output a rendered template.
|
||||
* @param string $name
|
||||
* @param array $data
|
||||
* @return null
|
||||
*/
|
||||
public function insert($name, array $data = array())
|
||||
{
|
||||
echo $this->engine->render($name, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply multiple functions to variable.
|
||||
* @param mixed $var
|
||||
* @param string $functions
|
||||
* @return mixed
|
||||
*/
|
||||
public function batch($var, $functions)
|
||||
{
|
||||
foreach (explode('|', $functions) as $function) {
|
||||
if ($this->engine->doesFunctionExist($function)) {
|
||||
$var = call_user_func(array($this, $function), $var);
|
||||
} elseif (is_callable($function)) {
|
||||
$var = call_user_func($function, $var);
|
||||
} else {
|
||||
throw new LogicException(
|
||||
'The batch function could not find the "' . $function . '" function.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $var;
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape string.
|
||||
* @param string $string
|
||||
* @param null|string $functions
|
||||
* @return string
|
||||
*/
|
||||
public function escape($string, $functions = null)
|
||||
{
|
||||
static $flags;
|
||||
|
||||
if (!isset($flags)) {
|
||||
$flags = ENT_QUOTES | (defined('ENT_SUBSTITUTE') ? ENT_SUBSTITUTE : 0);
|
||||
}
|
||||
|
||||
if ($functions) {
|
||||
$string = $this->batch($string, $functions);
|
||||
}
|
||||
|
||||
return htmlspecialchars($string, $flags, 'UTF-8');
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias to escape function.
|
||||
* @param string $string
|
||||
* @param null|string $functions
|
||||
* @return string
|
||||
*/
|
||||
public function e($string, $functions = null)
|
||||
{
|
||||
return $this->escape($string, $functions);
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
<?php
|
||||
|
||||
include 'Engine.php';
|
||||
include 'Extension/ExtensionInterface.php';
|
||||
include 'Template/Data.php';
|
||||
include 'Template/Directory.php';
|
||||
include 'Template/FileExtension.php';
|
||||
include 'Template/Folders.php';
|
||||
include 'Template/Func.php';
|
||||
include 'Template/Functions.php';
|
||||
include 'Template/Name.php';
|
||||
include 'Template/Template.php';
|
||||
// Create new Plates instance
|
||||
$templates = new League\Plates\Engine('templates');
|
||||
|
||||
// Preassign data to the layout
|
||||
$templates->addData(['company' => 'The Company Name'], 'layout');
|
||||
|
||||
// Render a template
|
||||
echo $templates->render('profile', ['name' => 'Jonathan']);
|
||||
@@ -1,12 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<title><?=$this->e($title)?> | <?=$this->e($company)?></title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<?=$this->section('content')?>
|
||||
|
||||
<?=$this->section('scripts')?>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,12 +0,0 @@
|
||||
<?php $this->layout('layout', ['title' => 'User Profile']) ?>
|
||||
|
||||
<h1>User Profile</h1>
|
||||
<p>Hello, <?=$this->e($name)?>!</p>
|
||||
|
||||
<?php $this->insert('sidebar') ?>
|
||||
|
||||
<?php $this->push('scripts') ?>
|
||||
<script>
|
||||
// Some JavaScript
|
||||
</script>
|
||||
<?php $this->end() ?>
|
||||
@@ -1,6 +0,0 @@
|
||||
<ul>
|
||||
<li><a href="#link">Example sidebar link</a></li>
|
||||
<li><a href="#link">Example sidebar link</a></li>
|
||||
<li><a href="#link">Example sidebar link</a></li>
|
||||
<li><a href="#link">Example sidebar link</a></li>
|
||||
</ul>
|
||||
@@ -1,2535 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace utilphp;
|
||||
|
||||
/**
|
||||
* util.php
|
||||
*
|
||||
* util.php is a library of helper functions for common tasks such as
|
||||
* formatting bytes as a string or displaying a date in terms of how long ago
|
||||
* it was in human readable terms (E.g. 4 minutes ago). The library is entirely
|
||||
* contained within a single file and hosts no dependencies. The library is
|
||||
* designed to avoid any possible conflicts.
|
||||
*
|
||||
* @author Brandon Wamboldt <brandon.wamboldt@gmail.com>
|
||||
* @link http://github.com/brandonwamboldt/utilphp/ Official Documentation
|
||||
*/
|
||||
class util
|
||||
{
|
||||
/**
|
||||
* A constant representing the number of seconds in a minute, for
|
||||
* making code more verbose
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
const SECONDS_IN_A_MINUTE = 60;
|
||||
|
||||
/**
|
||||
* A constant representing the number of seconds in an hour, for making
|
||||
* code more verbose
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
const SECONDS_IN_A_HOUR = 3600;
|
||||
const SECONDS_IN_AN_HOUR = 3600;
|
||||
|
||||
/**
|
||||
* A constant representing the number of seconds in a day, for making
|
||||
* code more verbose
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
const SECONDS_IN_A_DAY = 86400;
|
||||
|
||||
/**
|
||||
* A constant representing the number of seconds in a week, for making
|
||||
* code more verbose
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
const SECONDS_IN_A_WEEK = 604800;
|
||||
|
||||
/**
|
||||
* A constant representing the number of seconds in a month (30 days),
|
||||
* for making code more verbose
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
const SECONDS_IN_A_MONTH = 2592000;
|
||||
|
||||
/**
|
||||
* A constant representing the number of seconds in a year (365 days),
|
||||
* for making code more verbose
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
const SECONDS_IN_A_YEAR = 31536000;
|
||||
|
||||
/**
|
||||
* URL constants as defined in the PHP Manual under "Constants usable with
|
||||
* http_build_url()".
|
||||
*
|
||||
* @see http://us2.php.net/manual/en/http.constants.php#http.constants.url
|
||||
*/
|
||||
const HTTP_URL_REPLACE = 1;
|
||||
const HTTP_URL_JOIN_PATH = 2;
|
||||
const HTTP_URL_JOIN_QUERY = 4;
|
||||
const HTTP_URL_STRIP_USER = 8;
|
||||
const HTTP_URL_STRIP_PASS = 16;
|
||||
const HTTP_URL_STRIP_AUTH = 32;
|
||||
const HTTP_URL_STRIP_PORT = 64;
|
||||
const HTTP_URL_STRIP_PATH = 128;
|
||||
const HTTP_URL_STRIP_QUERY = 256;
|
||||
const HTTP_URL_STRIP_FRAGMENT = 512;
|
||||
const HTTP_URL_STRIP_ALL = 1024;
|
||||
|
||||
/**
|
||||
* A collapse icon, using in the dump_var function to allow collapsing
|
||||
* an array or object
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $icon_collapse = 'iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAMAAADXT/YiAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2RpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo3MjlFRjQ2NkM5QzJFMTExOTA0MzkwRkI0M0ZCODY4RCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpFNzFDNDQyNEMyQzkxMUUxOTU4MEM4M0UxRDA0MUVGNSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpFNzFDNDQyM0MyQzkxMUUxOTU4MEM4M0UxRDA0MUVGNSIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IFdpbmRvd3MiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo3NDlFRjQ2NkM5QzJFMTExOTA0MzkwRkI0M0ZCODY4RCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo3MjlFRjQ2NkM5QzJFMTExOTA0MzkwRkI0M0ZCODY4RCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PuF4AWkAAAA2UExURU9t2DBStczM/1h16DNmzHiW7iNFrypMvrnD52yJ4ezs7Onp6ejo6P///+Tk5GSG7D9h5SRGq0Q2K74AAAA/SURBVHjaLMhZDsAgDANRY3ZISnP/y1ZWeV+jAeuRSky6cKL4ryDdSggP8UC7r6GvR1YHxjazPQDmVzI/AQYAnFQDdVSJ80EAAAAASUV
Line truncated
|
||||
|
||||
/**
|
||||
* A collapse icon, using in the dump_var function to allow collapsing
|
||||
* an array or object
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $icon_expand = 'iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAMAAADXT/YiAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2RpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo3MTlFRjQ2NkM5QzJFMTExOTA0MzkwRkI0M0ZCODY4RCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpFQzZERTJDNEMyQzkxMUUxODRCQzgyRUNDMzZEQkZFQiIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpFQzZERTJDM0MyQzkxMUUxODRCQzgyRUNDMzZEQkZFQiIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IFdpbmRvd3MiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo3MzlFRjQ2NkM5QzJFMTExOTA0MzkwRkI0M0ZCODY4RCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo3MTlFRjQ2NkM5QzJFMTExOTA0MzkwRkI0M0ZCODY4RCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PkmDvWIAAABIUExURU9t2MzM/3iW7ubm59/f5urq85mZzOvr6////9ra38zMzObm5rfB8FZz5myJ4SNFrypMvjBStTNmzOvr+mSG7OXl8T9h5SRGq/OfqCEAAABKSURBVHjaFMlbEoAwCEPRULXF2jdW9r9T4czcyUdA4XWB0IgdNSybxU9amMzHzDlPKKu7Fd1e6+wY195jW
Line truncated
|
||||
|
||||
private static $hasArray = false;
|
||||
|
||||
/**
|
||||
* Map of special non-ASCII characters and suitable ASCII replacement
|
||||
* characters.
|
||||
*
|
||||
* Part of the URLify.php Project <https://github.com/jbroadway/urlify/>
|
||||
*
|
||||
* @see https://github.com/jbroadway/urlify/blob/master/URLify.php
|
||||
*/
|
||||
public static $maps = array(
|
||||
'de' => array(/* German */
|
||||
'Ä' => 'Ae', 'Ö' => 'Oe', 'Ü' => 'Ue', 'ä' => 'ae', 'ö' => 'oe', 'ü' => 'ue', 'ß' => 'ss',
|
||||
'ẞ' => 'SS'
|
||||
),
|
||||
'latin' => array(
|
||||
'À' => 'A', 'Á' => 'A', 'Â' => 'A', 'Ã' => 'A', 'Ä' => 'A', 'Å' => 'A','Ă' => 'A', 'Æ' => 'AE', 'Ç' =>
|
||||
'C', 'È' => 'E', 'É' => 'E', 'Ê' => 'E', 'Ë' => 'E', 'Ì' => 'I', 'Í' => 'I', 'Î' => 'I',
|
||||
'Ï' => 'I', 'Ð' => 'D', 'Ñ' => 'N', 'Ò' => 'O', 'Ó' => 'O', 'Ô' => 'O', 'Õ' => 'O', 'Ö' =>
|
||||
'O', 'Ő' => 'O', 'Ø' => 'O','Ș' => 'S','Ț' => 'T', 'Ù' => 'U', 'Ú' => 'U', 'Û' => 'U', 'Ü' => 'U', 'Ű' => 'U',
|
||||
'Ý' => 'Y', 'Þ' => 'TH', 'ß' => 'ss', 'à' => 'a', 'á' => 'a', 'â' => 'a', 'ã' => 'a', 'ä' =>
|
||||
'a', 'å' => 'a', 'ă' => 'a', 'æ' => 'ae', 'ç' => 'c', 'è' => 'e', 'é' => 'e', 'ê' => 'e', 'ë' => 'e',
|
||||
'ì' => 'i', 'í' => 'i', 'î' => 'i', 'ï' => 'i', 'ð' => 'd', 'ñ' => 'n', 'ò' => 'o', 'ó' =>
|
||||
'o', 'ô' => 'o', 'õ' => 'o', 'ö' => 'o', 'ő' => 'o', 'ø' => 'o', 'ș' => 's', 'ț' => 't', 'ù' => 'u', 'ú' => 'u',
|
||||
'û' => 'u', 'ü' => 'u', 'ű' => 'u', 'ý' => 'y', 'þ' => 'th', 'ÿ' => 'y'
|
||||
),
|
||||
'latin_symbols' => array(
|
||||
'©' => '(c)'
|
||||
),
|
||||
'el' => array(/* Greek */
|
||||
'α' => 'a', 'β' => 'b', 'γ' => 'g', 'δ' => 'd', 'ε' => 'e', 'ζ' => 'z', 'η' => 'h', 'θ' => '8',
|
||||
'ι' => 'i', 'κ' => 'k', 'λ' => 'l', 'μ' => 'm', 'ν' => 'n', 'ξ' => '3', 'ο' => 'o', 'π' => 'p',
|
||||
'ρ' => 'r', 'σ' => 's', 'τ' => 't', 'υ' => 'y', 'φ' => 'f', 'χ' => 'x', 'ψ' => 'ps', 'ω' => 'w',
|
||||
'ά' => 'a', 'έ' => 'e', 'ί' => 'i', 'ό' => 'o', 'ύ' => 'y', 'ή' => 'h', 'ώ' => 'w', 'ς' => 's',
|
||||
'ϊ' => 'i', 'ΰ' => 'y', 'ϋ' => 'y', 'ΐ' => 'i',
|
||||
'Α' => 'A', 'Β' => 'B', 'Γ' => 'G', 'Δ' => 'D', 'Ε' => 'E', 'Ζ' => 'Z', 'Η' => 'H', 'Θ' => '8',
|
||||
'Ι' => 'I', 'Κ' => 'K', 'Λ' => 'L', 'Μ' => 'M', 'Ν' => 'N', 'Ξ' => '3', 'Ο' => 'O', 'Π' => 'P',
|
||||
'Ρ' => 'R', 'Σ' => 'S', 'Τ' => 'T', 'Υ' => 'Y', 'Φ' => 'F', 'Χ' => 'X', 'Ψ' => 'PS', 'Ω' => 'W',
|
||||
'Ά' => 'A', 'Έ' => 'E', 'Ί' => 'I', 'Ό' => 'O', 'Ύ' => 'Y', 'Ή' => 'H', 'Ώ' => 'W', 'Ϊ' => 'I',
|
||||
'Ϋ' => 'Y'
|
||||
),
|
||||
'tr' => array(/* Turkish */
|
||||
'ş' => 's', 'Ş' => 'S', 'ı' => 'i', 'İ' => 'I', 'ç' => 'c', 'Ç' => 'C', 'ü' => 'u', 'Ü' => 'U',
|
||||
'ö' => 'o', 'Ö' => 'O', 'ğ' => 'g', 'Ğ' => 'G'
|
||||
),
|
||||
'ru' => array(/* Russian */
|
||||
'а' => 'a', 'б' => 'b', 'в' => 'v', 'г' => 'g', 'д' => 'd', 'е' => 'e', 'ё' => 'yo', 'ж' => 'zh',
|
||||
'з' => 'z', 'и' => 'i', 'й' => 'j', 'к' => 'k', 'л' => 'l', 'м' => 'm', 'н' => 'n', 'о' => 'o',
|
||||
'п' => 'p', 'р' => 'r', 'с' => 's', 'т' => 't', 'у' => 'u', 'ф' => 'f', 'х' => 'h', 'ц' => 'c',
|
||||
'ч' => 'ch', 'ш' => 'sh', 'щ' => 'sh', 'ъ' => '', 'ы' => 'y', 'ь' => '', 'э' => 'e', 'ю' => 'yu',
|
||||
'я' => 'ya',
|
||||
'А' => 'A', 'Б' => 'B', 'В' => 'V', 'Г' => 'G', 'Д' => 'D', 'Е' => 'E', 'Ё' => 'Yo', 'Ж' => 'Zh',
|
||||
'З' => 'Z', 'И' => 'I', 'Й' => 'J', 'К' => 'K', 'Л' => 'L', 'М' => 'M', 'Н' => 'N', 'О' => 'O',
|
||||
'П' => 'P', 'Р' => 'R', 'С' => 'S', 'Т' => 'T', 'У' => 'U', 'Ф' => 'F', 'Х' => 'H', 'Ц' => 'C',
|
||||
'Ч' => 'Ch', 'Ш' => 'Sh', 'Щ' => 'Sh', 'Ъ' => '', 'Ы' => 'Y', 'Ь' => '', 'Э' => 'E', 'Ю' => 'Yu',
|
||||
'Я' => 'Ya',
|
||||
'№' => ''
|
||||
),
|
||||
'uk' => array(/* Ukrainian */
|
||||
'Є' => 'Ye', 'І' => 'I', 'Ї' => 'Yi', 'Ґ' => 'G', 'є' => 'ye', 'і' => 'i', 'ї' => 'yi', 'ґ' => 'g'
|
||||
),
|
||||
'cs' => array(/* Czech */
|
||||
'č' => 'c', 'ď' => 'd', 'ě' => 'e', 'ň' => 'n', 'ř' => 'r', 'š' => 's', 'ť' => 't', 'ů' => 'u',
|
||||
'ž' => 'z', 'Č' => 'C', 'Ď' => 'D', 'Ě' => 'E', 'Ň' => 'N', 'Ř' => 'R', 'Š' => 'S', 'Ť' => 'T',
|
||||
'Ů' => 'U', 'Ž' => 'Z'
|
||||
),
|
||||
'pl' => array(/* Polish */
|
||||
'ą' => 'a', 'ć' => 'c', 'ę' => 'e', 'ł' => 'l', 'ń' => 'n', 'ó' => 'o', 'ś' => 's', 'ź' => 'z',
|
||||
'ż' => 'z', 'Ą' => 'A', 'Ć' => 'C', 'Ę' => 'e', 'Ł' => 'L', 'Ń' => 'N', 'Ó' => 'O', 'Ś' => 'S',
|
||||
'Ź' => 'Z', 'Ż' => 'Z'
|
||||
),
|
||||
'ro' => array(/* Romanian */
|
||||
'ă' => 'a', 'â' => 'a', 'î' => 'i', 'ș' => 's', 'ț' => 't', 'Ţ' => 'T', 'ţ' => 't'
|
||||
),
|
||||
'lv' => array(/* Latvian */
|
||||
'ā' => 'a', 'č' => 'c', 'ē' => 'e', 'ģ' => 'g', 'ī' => 'i', 'ķ' => 'k', 'ļ' => 'l', 'ņ' => 'n',
|
||||
'š' => 's', 'ū' => 'u', 'ž' => 'z', 'Ā' => 'A', 'Č' => 'C', 'Ē' => 'E', 'Ģ' => 'G', 'Ī' => 'i',
|
||||
'Ķ' => 'k', 'Ļ' => 'L', 'Ņ' => 'N', 'Š' => 'S', 'Ū' => 'u', 'Ž' => 'Z'
|
||||
),
|
||||
'lt' => array(/* Lithuanian */
|
||||
'ą' => 'a', 'č' => 'c', 'ę' => 'e', 'ė' => 'e', 'į' => 'i', 'š' => 's', 'ų' => 'u', 'ū' => 'u', 'ž' => 'z',
|
||||
'Ą' => 'A', 'Č' => 'C', 'Ę' => 'E', 'Ė' => 'E', 'Į' => 'I', 'Š' => 'S', 'Ų' => 'U', 'Ū' => 'U', 'Ž' => 'Z'
|
||||
),
|
||||
'vn' => array(/* Vietnamese */
|
||||
'Á' => 'A', 'À' => 'A', 'Ả' => 'A', 'Ã' => 'A', 'Ạ' => 'A', 'Ă' => 'A', 'Ắ' => 'A', 'Ằ' => 'A', 'Ẳ' => 'A', 'Ẵ' => 'A', 'Ặ' => 'A', 'Â' => 'A', 'Ấ' => 'A', 'Ầ' => 'A', 'Ẩ' => 'A', 'Ẫ' => 'A', 'Ậ' => 'A',
|
||||
'á' => 'a', 'à' => 'a', 'ả' => 'a', 'ã' => 'a', 'ạ' => 'a', 'ă' => 'a', 'ắ' => 'a', 'ằ' => 'a', 'ẳ' => 'a', 'ẵ' => 'a', 'ặ' => 'a', 'â' => 'a', 'ấ' => 'a', 'ầ' => 'a', 'ẩ' => 'a', 'ẫ' => 'a', 'ậ' => 'a',
|
||||
'É' => 'E', 'È' => 'E', 'Ẻ' => 'E', 'Ẽ' => 'E', 'Ẹ' => 'E', 'Ê' => 'E', 'Ế' => 'E', 'Ề' => 'E', 'Ể' => 'E', 'Ễ' => 'E', 'Ệ' => 'E',
|
||||
'é' => 'e', 'è' => 'e', 'ẻ' => 'e', 'ẽ' => 'e', 'ẹ' => 'e', 'ê' => 'e', 'ế' => 'e', 'ề' => 'e', 'ể' => 'e', 'ễ' => 'e', 'ệ' => 'e',
|
||||
'Í' => 'I', 'Ì' => 'I', 'Ỉ' => 'I', 'Ĩ' => 'I', 'Ị' => 'I', 'í' => 'i', 'ì' => 'i', 'ỉ' => 'i', 'ĩ' => 'i', 'ị' => 'i',
|
||||
'Ó' => 'O', 'Ò' => 'O', 'Ỏ' => 'O', 'Õ' => 'O', 'Ọ' => 'O', 'Ô' => 'O', 'Ố' => 'O', 'Ồ' => 'O', 'Ổ' => 'O', 'Ỗ' => 'O', 'Ộ' => 'O', 'Ơ' => 'O', 'Ớ' => 'O', 'Ờ' => 'O', 'Ở' => 'O', 'Ỡ' => 'O', 'Ợ' => 'O',
|
||||
'ó' => 'o', 'ò' => 'o', 'ỏ' => 'o', 'õ' => 'o', 'ọ' => 'o', 'ô' => 'o', 'ố' => 'o', 'ồ' => 'o', 'ổ' => 'o', 'ỗ' => 'o', 'ộ' => 'o', 'ơ' => 'o', 'ớ' => 'o', 'ờ' => 'o', 'ở' => 'o', 'ỡ' => 'o', 'ợ' => 'o',
|
||||
'Ú' => 'U', 'Ù' => 'U', 'Ủ' => 'U', 'Ũ' => 'U', 'Ụ' => 'U', 'Ư' => 'U', 'Ứ' => 'U', 'Ừ' => 'U', 'Ử' => 'U', 'Ữ' => 'U', 'Ự' => 'U',
|
||||
'ú' => 'u', 'ù' => 'u', 'ủ' => 'u', 'ũ' => 'u', 'ụ' => 'u', 'ư' => 'u', 'ứ' => 'u', 'ừ' => 'u', 'ử' => 'u', 'ữ' => 'u', 'ự' => 'u',
|
||||
'Ý' => 'Y', 'Ỳ' => 'Y', 'Ỷ' => 'Y', 'Ỹ' => 'Y', 'Ỵ' => 'Y', 'ý' => 'y', 'ỳ' => 'y', 'ỷ' => 'y', 'ỹ' => 'y', 'ỵ' => 'y',
|
||||
'Đ' => 'D', 'đ' => 'd'
|
||||
),
|
||||
'ar' => array(/* Arabic */
|
||||
'أ' => 'a', 'ب' => 'b', 'ت' => 't', 'ث' => 'th', 'ج' => 'g', 'ح' => 'h', 'خ' => 'kh', 'د' => 'd',
|
||||
'ذ' => 'th', 'ر' => 'r', 'ز' => 'z', 'س' => 's', 'ش' => 'sh', 'ص' => 's', 'ض' => 'd', 'ط' => 't',
|
||||
'ظ' => 'th', 'ع' => 'aa', 'غ' => 'gh', 'ف' => 'f', 'ق' => 'k', 'ك' => 'k', 'ل' => 'l', 'م' => 'm',
|
||||
'ن' => 'n', 'ه' => 'h', 'و' => 'o', 'ي' => 'y'
|
||||
),
|
||||
'sr' => array(/* Serbian */
|
||||
'ђ' => 'dj', 'ј' => 'j', 'љ' => 'lj', 'њ' => 'nj', 'ћ' => 'c', 'џ' => 'dz', 'đ' => 'dj',
|
||||
'Ђ' => 'Dj', 'Ј' => 'j', 'Љ' => 'Lj', 'Њ' => 'Nj', 'Ћ' => 'C', 'Џ' => 'Dz', 'Đ' => 'Dj'
|
||||
),
|
||||
'az' => array(/* Azerbaijani */
|
||||
'ç' => 'c', 'ə' => 'e', 'ğ' => 'g', 'ı' => 'i', 'ö' => 'o', 'ş' => 's', 'ü' => 'u',
|
||||
'Ç' => 'C', 'Ə' => 'E', 'Ğ' => 'G', 'İ' => 'I', 'Ö' => 'O', 'Ş' => 'S', 'Ü' => 'U'
|
||||
),
|
||||
);
|
||||
|
||||
/**
|
||||
* The character map for the designated language
|
||||
*
|
||||
* @see https://github.com/jbroadway/urlify/blob/master/URLify.php
|
||||
*/
|
||||
private static $map = array();
|
||||
|
||||
/**
|
||||
* The character list as a string.
|
||||
*
|
||||
* @see https://github.com/jbroadway/urlify/blob/master/URLify.php
|
||||
*/
|
||||
private static $chars = '';
|
||||
|
||||
/**
|
||||
* The character list as a regular expression.
|
||||
*
|
||||
* @see https://github.com/jbroadway/urlify/blob/master/URLify.php
|
||||
*/
|
||||
private static $regex = '';
|
||||
|
||||
/**
|
||||
* The current language
|
||||
*
|
||||
* @see https://github.com/jbroadway/urlify/blob/master/URLify.php
|
||||
*/
|
||||
private static $language = '';
|
||||
|
||||
/**
|
||||
* Initializes the character map.
|
||||
*
|
||||
* Part of the URLify.php Project <https://github.com/jbroadway/urlify/>
|
||||
*
|
||||
* @see https://github.com/jbroadway/urlify/blob/master/URLify.php
|
||||
*/
|
||||
private static function initLanguageMap($language = '')
|
||||
{
|
||||
if (count(self::$map) > 0 && (($language == '') || ($language == self::$language))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Is a specific map associated with $language?
|
||||
if (isset(self::$maps[$language]) && is_array(self::$maps[$language])) {
|
||||
// Move this map to end. This means it will have priority over others
|
||||
$m = self::$maps[$language];
|
||||
unset(self::$maps[$language]);
|
||||
self::$maps[$language] = $m;
|
||||
}
|
||||
|
||||
// Reset static vars
|
||||
self::$language = $language;
|
||||
self::$map = array();
|
||||
self::$chars = '';
|
||||
|
||||
foreach (self::$maps as $map) {
|
||||
foreach ($map as $orig => $conv) {
|
||||
self::$map[$orig] = $conv;
|
||||
self::$chars .= $orig;
|
||||
}
|
||||
}
|
||||
|
||||
self::$regex = '/[' . self::$chars . ']/u';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Access an array index, retrieving the value stored there if it
|
||||
* exists or a default if it does not. This function allows you to
|
||||
* concisely access an index which may or may not exist without
|
||||
* raising a warning.
|
||||
*
|
||||
* @param array $var Array value to access
|
||||
* @param mixed $default Default value to return if the key is not
|
||||
* present in the array
|
||||
* @return mixed
|
||||
*/
|
||||
public static function array_get(&$var, $default = null)
|
||||
{
|
||||
if (isset($var)) {
|
||||
return $var;
|
||||
}
|
||||
|
||||
return $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a variable's contents using nice HTML formatting and will
|
||||
* properly display the value of booleans as true or false
|
||||
*
|
||||
* @see var_dump_plain()
|
||||
*
|
||||
* @param mixed $var The variable to dump
|
||||
* @return string
|
||||
*/
|
||||
public static function var_dump($var, $return = false, $expandLevel = 1)
|
||||
{
|
||||
self::$hasArray = false;
|
||||
$toggScript = 'var colToggle = function(toggID) {var img = document.getElementById(toggID);if (document.getElementById(toggID + "-collapsable").style.display == "none") {document.getElementById(toggID + "-collapsable").style.display = "inline";setImg(toggID, 0);var previousSibling = document.getElementById(toggID + "-collapsable").previousSibling;while (previousSibling != null && (previousSibling.nodeType != 1 || previousSibling.tagName.toLowerCase() != "br")) {previousSibling = previousSibling.previousSibling;}} else {document.getElementById(toggID + "-collapsable").style.display = "none";setImg(toggID, 1);var previousSibling = document.getElementById(toggID + "-collapsable").previousSibling; while (previousSibling != null && (previousSibling.nodeType != 1 || previousSibling.tagName.toLowerCase() != "br")) {previousSibling = previousSibling.previousSibling;}}};';
|
||||
$imgScript = 'var setImg = function(objID,imgID,addStyle) {var imgStore = ["data:image/png;base64,' . self::$icon_collapse . '", "data:image/png;base64,' . self::$icon_expand . '"];if (objID) {document.getElementById(objID).setAttribute("src", imgStore[imgID]);if (addStyle){document.getElementById(objID).setAttribute("style", "position:relative;left:-5px;top:-1px;cursor:pointer;");}}};';
|
||||
$jsCode = preg_replace('/ +/', ' ', '<script>' . $toggScript . $imgScript . '</script>');
|
||||
$html = '<pre style="margin-bottom: 18px;' .
|
||||
'background: #f7f7f9;' .
|
||||
'border: 1px solid #e1e1e8;' .
|
||||
'padding: 8px;' .
|
||||
'border-radius: 4px;' .
|
||||
'-moz-border-radius: 4px;' .
|
||||
'-webkit-border radius: 4px;' .
|
||||
'display: block;' .
|
||||
'font-size: 12.05px;' .
|
||||
'white-space: pre-wrap;' .
|
||||
'word-wrap: break-word;' .
|
||||
'color: #333;' .
|
||||
'font-family: Menlo,Monaco,Consolas,\'Courier New\',monospace;">';
|
||||
$done = array();
|
||||
$html .= self::var_dump_plain($var, intval($expandLevel), 0, $done);
|
||||
$html .= '</pre>';
|
||||
|
||||
if (self::$hasArray) {
|
||||
$html = $jsCode . $html;
|
||||
}
|
||||
|
||||
if (!$return) {
|
||||
echo $html;
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a variable's contents using nice HTML formatting (Without
|
||||
* the <pre> tag) and will properly display the values of variables
|
||||
* like booleans and resources. Supports collapsable arrays and objects
|
||||
* as well.
|
||||
*
|
||||
* @param mixed $var The variable to dump
|
||||
* @return string
|
||||
*/
|
||||
public static function var_dump_plain($var, $expLevel, $depth = 0, $done = array())
|
||||
{
|
||||
$html = '';
|
||||
|
||||
if ($expLevel > 0) {
|
||||
$expLevel--;
|
||||
$setImg = 0;
|
||||
$setStyle = 'display:inline;';
|
||||
} elseif ($expLevel == 0) {
|
||||
$setImg = 1;
|
||||
$setStyle='display:none;';
|
||||
} elseif ($expLevel < 0) {
|
||||
$setImg = 0;
|
||||
$setStyle = 'display:inline;';
|
||||
}
|
||||
|
||||
if (is_bool($var)) {
|
||||
$html .= '<span style="color:#588bff;">bool</span><span style="color:#999;">(</span><strong>' . (($var) ? 'true' : 'false') . '</strong><span style="color:#999;">)</span>';
|
||||
} elseif (is_int($var)) {
|
||||
$html .= '<span style="color:#588bff;">int</span><span style="color:#999;">(</span><strong>' . $var . '</strong><span style="color:#999;">)</span>';
|
||||
} elseif (is_float($var)) {
|
||||
$html .= '<span style="color:#588bff;">float</span><span style="color:#999;">(</span><strong>' . $var . '</strong><span style="color:#999;">)</span>';
|
||||
} elseif (is_string($var)) {
|
||||
$html .= '<span style="color:#588bff;">string</span><span style="color:#999;">(</span>' . strlen($var) . '<span style="color:#999;">)</span> <strong>"' . self::htmlentities($var) . '"</strong>';
|
||||
} elseif (is_null($var)) {
|
||||
$html .= '<strong>NULL</strong>';
|
||||
} elseif (is_resource($var)) {
|
||||
$html .= '<span style="color:#588bff;">resource</span>("' . get_resource_type($var) . '") <strong>"' . $var . '"</strong>';
|
||||
} elseif (is_array($var)) {
|
||||
// Check for recursion
|
||||
if ($depth > 0) {
|
||||
foreach ($done as $prev) {
|
||||
if ($prev === $var) {
|
||||
$html .= '<span style="color:#588bff;">array</span>(' . count($var) . ') *RECURSION DETECTED*';
|
||||
return $html;
|
||||
}
|
||||
}
|
||||
|
||||
// Keep track of variables we have already processed to detect recursion
|
||||
$done[] = &$var;
|
||||
}
|
||||
|
||||
self::$hasArray = true;
|
||||
$uuid = 'include-php-' . uniqid() . mt_rand(1, 1000000);
|
||||
|
||||
$html .= (!empty($var) ? ' <img id="' . $uuid . '" src="data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs%3D" onclick="javascript:colToggle(this.id);" /><script>setImg("' . $uuid . '",'.$setImg.',1);</script>' : '') . '<span style="color:#588bff;">array</span>(' . count($var) . ')';
|
||||
if (!empty($var)) {
|
||||
$html .= ' <span id="' . $uuid . '-collapsable" style="'.$setStyle.'"><br />[<br />';
|
||||
|
||||
$indent = 4;
|
||||
$longest_key = 0;
|
||||
|
||||
foreach ($var as $key => $value) {
|
||||
if (is_string($key)) {
|
||||
$longest_key = max($longest_key, strlen($key) + 2);
|
||||
} else {
|
||||
$longest_key = max($longest_key, strlen($key));
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($var as $key => $value) {
|
||||
if (is_numeric($key)) {
|
||||
$html .= str_repeat(' ', $indent) . str_pad($key, $longest_key, ' ');
|
||||
} else {
|
||||
$html .= str_repeat(' ', $indent) . str_pad('"' . self::htmlentities($key) . '"', $longest_key, ' ');
|
||||
}
|
||||
|
||||
$html .= ' => ';
|
||||
|
||||
$value = explode('<br />', self::var_dump_plain($value, $expLevel, $depth + 1, $done));
|
||||
|
||||
foreach ($value as $line => $val) {
|
||||
if ($line != 0) {
|
||||
$value[$line] = str_repeat(' ', $indent * 2) . $val;
|
||||
}
|
||||
}
|
||||
|
||||
$html .= implode('<br />', $value) . '<br />';
|
||||
}
|
||||
|
||||
$html .= ']</span>';
|
||||
}
|
||||
} elseif (is_object($var)) {
|
||||
// Check for recursion
|
||||
foreach ($done as $prev) {
|
||||
if ($prev === $var) {
|
||||
$html .= '<span style="color:#588bff;">object</span>(' . get_class($var) . ') *RECURSION DETECTED*';
|
||||
return $html;
|
||||
}
|
||||
}
|
||||
|
||||
// Keep track of variables we have already processed to detect recursion
|
||||
$done[] = &$var;
|
||||
|
||||
self::$hasArray=true;
|
||||
$uuid = 'include-php-' . uniqid() . mt_rand(1, 1000000);
|
||||
|
||||
$html .= ' <img id="' . $uuid . '" src="data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs%3D" onclick="javascript:colToggle(this.id);" /><script>setImg("' . $uuid . '",'.$setImg.',1);</script><span style="color:#588bff;">object</span>(' . get_class($var) . ') <span id="' . $uuid . '-collapsable" style="'.$setStyle.'"><br />[<br />';
|
||||
|
||||
$varArray = (array) $var;
|
||||
|
||||
$indent = 4;
|
||||
$longest_key = 0;
|
||||
|
||||
foreach ($varArray as $key => $value) {
|
||||
if (substr($key, 0, 2) == "\0*") {
|
||||
unset($varArray[$key]);
|
||||
$key = 'protected:' . substr($key, 3);
|
||||
$varArray[$key] = $value;
|
||||
} elseif (substr($key, 0, 1) == "\0") {
|
||||
unset($varArray[$key]);
|
||||
$key = 'private:' . substr($key, 1, strpos(substr($key, 1), "\0")) . ':' . substr($key, strpos(substr($key, 1), "\0") + 2);
|
||||
$varArray[$key] = $value;
|
||||
}
|
||||
|
||||
if (is_string($key)) {
|
||||
$longest_key = max($longest_key, strlen($key) + 2);
|
||||
} else {
|
||||
$longest_key = max($longest_key, strlen($key));
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($varArray as $key => $value) {
|
||||
if (is_numeric($key)) {
|
||||
$html .= str_repeat(' ', $indent) . str_pad($key, $longest_key, ' ');
|
||||
} else {
|
||||
$html .= str_repeat(' ', $indent) . str_pad('"' . self::htmlentities($key) . '"', $longest_key, ' ');
|
||||
}
|
||||
|
||||
$html .= ' => ';
|
||||
|
||||
$value = explode('<br />', self::var_dump_plain($value, $expLevel, $depth + 1, $done));
|
||||
|
||||
foreach ($value as $line => $val) {
|
||||
if ($line != 0) {
|
||||
$value[$line] = str_repeat(' ', $indent * 2) . $val;
|
||||
}
|
||||
}
|
||||
|
||||
$html .= implode('<br />', $value) . '<br />';
|
||||
}
|
||||
|
||||
$html .= ']</span>';
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts any accent characters to their equivalent normal characters
|
||||
* and converts any other non-alphanumeric characters to dashes, then
|
||||
* converts any sequence of two or more dashes to a single dash. This
|
||||
* function generates slugs safe for use as URLs, and if you pass true
|
||||
* as the second parameter, it will create strings safe for use as CSS
|
||||
* classes or IDs.
|
||||
*
|
||||
* @param string $string A string to convert to a slug
|
||||
* @param string $separator The string to separate words with
|
||||
* @param boolean $css_mode Whether or not to generate strings safe for
|
||||
* CSS classes/IDs (Default to false)
|
||||
* @return string
|
||||
*/
|
||||
public static function slugify($string, $separator = '-', $css_mode = false)
|
||||
{
|
||||
// Compatibility with 1.0.* parameter ordering for semvar
|
||||
if ($separator === true || $separator === false) {
|
||||
$css_mode = $separator;
|
||||
$separator = '-';
|
||||
|
||||
// Raise deprecation error
|
||||
trigger_error(
|
||||
'util::slugify() now takes $css_mode as the third parameter, please update your code',
|
||||
E_USER_DEPRECATED
|
||||
);
|
||||
}
|
||||
|
||||
$slug = preg_replace('/([^a-z0-9]+)/', $separator, strtolower(self::remove_accents($string)));
|
||||
|
||||
if ($css_mode) {
|
||||
$digits = array('zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine');
|
||||
|
||||
if (is_numeric(substr($slug, 0, 1))) {
|
||||
$slug = $digits[substr($slug, 0, 1)] . substr($slug, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return $slug;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if a string is utf8 encoded.
|
||||
*
|
||||
* NOTE: This function checks for 5-Byte sequences, UTF8
|
||||
* has Bytes Sequences with a maximum length of 4.
|
||||
*
|
||||
* Written by Tony Ferrara <http://blog.ircmaxwell.com>
|
||||
*
|
||||
* @param string $string The string to be checked
|
||||
* @return boolean
|
||||
*/
|
||||
public static function seems_utf8($string)
|
||||
{
|
||||
if (function_exists('mb_check_encoding')) {
|
||||
// If mbstring is available, this is significantly faster than
|
||||
// using PHP regexps.
|
||||
return mb_check_encoding($string, 'UTF-8');
|
||||
}
|
||||
|
||||
// @codeCoverageIgnoreStart
|
||||
return self::seemsUtf8Regex($string);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
/**
|
||||
* A non-Mbstring UTF-8 checker.
|
||||
*
|
||||
* @param $string
|
||||
* @return bool
|
||||
*/
|
||||
protected static function seemsUtf8Regex($string)
|
||||
{
|
||||
// Obtained from http://stackoverflow.com/a/11709412/430062 with permission.
|
||||
$regex = '/(
|
||||
[\xC0-\xC1] # Invalid UTF-8 Bytes
|
||||
| [\xF5-\xFF] # Invalid UTF-8 Bytes
|
||||
| \xE0[\x80-\x9F] # Overlong encoding of prior code point
|
||||
| \xF0[\x80-\x8F] # Overlong encoding of prior code point
|
||||
| [\xC2-\xDF](?![\x80-\xBF]) # Invalid UTF-8 Sequence Start
|
||||
| [\xE0-\xEF](?![\x80-\xBF]{2}) # Invalid UTF-8 Sequence Start
|
||||
| [\xF0-\xF4](?![\x80-\xBF]{3}) # Invalid UTF-8 Sequence Start
|
||||
| (?<=[\x0-\x7F\xF5-\xFF])[\x80-\xBF] # Invalid UTF-8 Sequence Middle
|
||||
| (?<![\xC2-\xDF]|[\xE0-\xEF]|[\xE0-\xEF][\x80-\xBF]|[\xF0-\xF4]|[\xF0-\xF4][\x80-\xBF]|[\xF0-\xF4][\x80-\xBF]{2})[\x80-\xBF] # Overlong Sequence
|
||||
| (?<=[\xE0-\xEF])[\x80-\xBF](?![\x80-\xBF]) # Short 3 byte sequence
|
||||
| (?<=[\xF0-\xF4])[\x80-\xBF](?![\x80-\xBF]{2}) # Short 4 byte sequence
|
||||
| (?<=[\xF0-\xF4][\x80-\xBF])[\x80-\xBF](?![\x80-\xBF]) # Short 4 byte sequence (2)
|
||||
)/x';
|
||||
|
||||
return ! preg_match($regex, $string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Nice formatting for computer sizes (Bytes).
|
||||
*
|
||||
* @param integer $bytes The number in bytes to format
|
||||
* @param integer $decimals The number of decimal points to include
|
||||
* @return string
|
||||
*/
|
||||
public static function size_format($bytes, $decimals = 0)
|
||||
{
|
||||
$bytes = floatval($bytes);
|
||||
|
||||
if ($bytes < 1024) {
|
||||
return $bytes . ' B';
|
||||
} elseif ($bytes < pow(1024, 2)) {
|
||||
return number_format($bytes / 1024, $decimals, '.', '') . ' KiB';
|
||||
} elseif ($bytes < pow(1024, 3)) {
|
||||
return number_format($bytes / pow(1024, 2), $decimals, '.', '') . ' MiB';
|
||||
} elseif ($bytes < pow(1024, 4)) {
|
||||
return number_format($bytes / pow(1024, 3), $decimals, '.', '') . ' GiB';
|
||||
} elseif ($bytes < pow(1024, 5)) {
|
||||
return number_format($bytes / pow(1024, 4), $decimals, '.', '') . ' TiB';
|
||||
} elseif ($bytes < pow(1024, 6)) {
|
||||
return number_format($bytes / pow(1024, 5), $decimals, '.', '') . ' PiB';
|
||||
} else {
|
||||
return number_format($bytes / pow(1024, 5), $decimals, '.', '') . ' PiB';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize data, if needed.
|
||||
*
|
||||
* @param mixed $data Data that might need to be serialized
|
||||
* @return mixed
|
||||
*/
|
||||
public static function maybe_serialize($data)
|
||||
{
|
||||
if (is_array($data) || is_object($data)) {
|
||||
return serialize($data);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unserialize value only if it is serialized.
|
||||
*
|
||||
* @param string $data A variable that may or may not be serialized
|
||||
* @return mixed
|
||||
*/
|
||||
public static function maybe_unserialize($data)
|
||||
{
|
||||
// If it isn't a string, it isn't serialized
|
||||
if (!is_string($data)) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
$data = trim($data);
|
||||
|
||||
// Is it the serialized NULL value?
|
||||
if ($data === 'N;') {
|
||||
return null;
|
||||
}
|
||||
|
||||
$length = strlen($data);
|
||||
|
||||
// Check some basic requirements of all serialized strings
|
||||
if ($length < 4 || $data[1] !== ':' || ($data[$length - 1] !== ';' && $data[$length - 1] !== '}')) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
// $data is the serialized false value
|
||||
if ($data === 'b:0;') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Don't attempt to unserialize data that isn't serialized
|
||||
$uns = @unserialize($data);
|
||||
|
||||
// Data failed to unserialize?
|
||||
if ($uns === false) {
|
||||
$uns = @unserialize(self::fix_broken_serialization($data));
|
||||
|
||||
if ($uns === false) {
|
||||
return $data;
|
||||
} else {
|
||||
return $uns;
|
||||
}
|
||||
} else {
|
||||
return $uns;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check value to find if it was serialized.
|
||||
*
|
||||
* If $data is not an string, then returned value will always be false.
|
||||
* Serialized data is always a string.
|
||||
*
|
||||
* @param mixed $data Value to check to see if was serialized
|
||||
* @return boolean
|
||||
*/
|
||||
public static function is_serialized($data)
|
||||
{
|
||||
// If it isn't a string, it isn't serialized
|
||||
if (!is_string($data)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$data = trim($data);
|
||||
|
||||
// Is it the serialized NULL value?
|
||||
if ($data === 'N;') {
|
||||
return true;
|
||||
}
|
||||
// Is it a serialized boolean?
|
||||
elseif ($data === 'b:0;' || $data === 'b:1;') {
|
||||
return true;
|
||||
}
|
||||
|
||||
$length = strlen($data);
|
||||
|
||||
// Check some basic requirements of all serialized strings
|
||||
if ($length < 4 || $data[1] !== ':' || ($data[$length - 1] !== ';' && $data[$length - 1] !== '}')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return @unserialize($data) !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unserializes partially-corrupted arrays that occur sometimes. Addresses
|
||||
* specifically the `unserialize(): Error at offset xxx of yyy bytes` error.
|
||||
*
|
||||
* NOTE: This error can *frequently* occur with mismatched character sets
|
||||
* and higher-than-ASCII characters.
|
||||
*
|
||||
* Contributed by Theodore R. Smith of PHP Experts, Inc. <http://www.phpexperts.pro/>
|
||||
*
|
||||
* @param string $brokenSerializedData
|
||||
* @return string
|
||||
*/
|
||||
public static function fix_broken_serialization($brokenSerializedData)
|
||||
{
|
||||
$fixdSerializedData = preg_replace_callback('!s:(\d+):"(.*?)";!', function($matches) {
|
||||
$snip = $matches[2];
|
||||
return 's:' . strlen($snip) . ':"' . $snip . '";';
|
||||
}, $brokenSerializedData);
|
||||
|
||||
return $fixdSerializedData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if the page is being server over SSL or not
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static function is_https()
|
||||
{
|
||||
return isset($_SERVER['HTTPS']) && !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off';
|
||||
}
|
||||
|
||||
/**
|
||||
* Add or remove query arguments to the URL.
|
||||
*
|
||||
* @param mixed $newKey Either newkey or an associative array
|
||||
* @param mixed $newValue Either newvalue or oldquery or uri
|
||||
* @param mixed $uri URI or URL to append the queru/queries to.
|
||||
* @return string
|
||||
*/
|
||||
public static function add_query_arg($newKey, $newValue = null, $uri = null)
|
||||
{
|
||||
// Was an associative array of key => value pairs passed?
|
||||
if (is_array($newKey)) {
|
||||
$newParams = $newKey;
|
||||
|
||||
// Was the URL passed as an argument?
|
||||
if (!is_null($newValue)) {
|
||||
$uri = $newValue;
|
||||
} elseif (!is_null($uri)) {
|
||||
$uri = $uri;
|
||||
} else {
|
||||
$uri = self::array_get($_SERVER['REQUEST_URI'], '');
|
||||
}
|
||||
} else {
|
||||
$newParams = array($newKey => $newValue);
|
||||
|
||||
// Was the URL passed as an argument?
|
||||
$uri = is_null($uri) ? self::array_get($_SERVER['REQUEST_URI'], '') : $uri;
|
||||
}
|
||||
|
||||
// Parse the URI into it's components
|
||||
$puri = parse_url($uri);
|
||||
|
||||
if (isset($puri['query'])) {
|
||||
parse_str($puri['query'], $queryParams);
|
||||
$queryParams = array_merge($queryParams, $newParams);
|
||||
} elseif (isset($puri['path']) && strstr($puri['path'], '=') !== false) {
|
||||
$puri['query'] = $puri['path'];
|
||||
unset($puri['path']);
|
||||
parse_str($puri['query'], $queryParams);
|
||||
$queryParams = array_merge($queryParams, $newParams);
|
||||
} else {
|
||||
$queryParams = $newParams;
|
||||
}
|
||||
|
||||
// Strip out any query params that are set to false
|
||||
foreach ($queryParams as $param => $value) {
|
||||
if ($value === false) {
|
||||
unset($queryParams[$param]);
|
||||
}
|
||||
}
|
||||
|
||||
// Re-construct the query string
|
||||
$puri['query'] = http_build_query($queryParams);
|
||||
|
||||
// Re-construct the entire URL
|
||||
$nuri = self::http_build_url($puri);
|
||||
|
||||
// Make the URI consistent with our input
|
||||
if ($nuri[0] === '/' && strstr($uri, '/') === false) {
|
||||
$nuri = substr($nuri, 1);
|
||||
}
|
||||
|
||||
if ($nuri[0] === '?' && strstr($uri, '?') === false) {
|
||||
$nuri = substr($nuri, 1);
|
||||
}
|
||||
|
||||
return rtrim($nuri, '?');
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an item or list from the query string.
|
||||
*
|
||||
* @param string|array $keys Query key or keys to remove.
|
||||
* @param bool $uri When false uses the $_SERVER value
|
||||
* @return string
|
||||
*/
|
||||
public static function remove_query_arg($keys, $uri = null)
|
||||
{
|
||||
if (is_array($keys)) {
|
||||
return self::add_query_arg(array_combine($keys, array_fill(0, count($keys), null)), $uri);
|
||||
}
|
||||
|
||||
return self::add_query_arg(array($keys => null), $uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a URL.
|
||||
*
|
||||
* The parts of the second URL will be merged into the first according to
|
||||
* the flags argument.
|
||||
*
|
||||
* @author Jake Smith <theman@jakeasmith.com>
|
||||
* @see https://github.com/jakeasmith/http_build_url/
|
||||
*
|
||||
* @param mixed $url (part(s) of) an URL in form of a string or
|
||||
* associative array like parse_url() returns
|
||||
* @param mixed $parts same as the first argument
|
||||
* @param int $flags a bitmask of binary or'ed HTTP_URL constants;
|
||||
* HTTP_URL_REPLACE is the default
|
||||
* @param array $new_url if set, it will be filled with the parts of the
|
||||
* composed url like parse_url() would return
|
||||
* @return string
|
||||
*/
|
||||
public static function http_build_url($url, $parts = array(), $flags = self::HTTP_URL_REPLACE, &$new_url = array())
|
||||
{
|
||||
is_array($url) || $url = parse_url($url);
|
||||
is_array($parts) || $parts = parse_url($parts);
|
||||
|
||||
isset($url['query']) && is_string($url['query']) || $url['query'] = null;
|
||||
isset($parts['query']) && is_string($parts['query']) || $parts['query'] = null;
|
||||
|
||||
$keys = array('user', 'pass', 'port', 'path', 'query', 'fragment');
|
||||
|
||||
// HTTP_URL_STRIP_ALL and HTTP_URL_STRIP_AUTH cover several other flags.
|
||||
if ($flags & self::HTTP_URL_STRIP_ALL) {
|
||||
$flags |= self::HTTP_URL_STRIP_USER | self::HTTP_URL_STRIP_PASS
|
||||
| self::HTTP_URL_STRIP_PORT | self::HTTP_URL_STRIP_PATH
|
||||
| self::HTTP_URL_STRIP_QUERY | self::HTTP_URL_STRIP_FRAGMENT;
|
||||
} elseif ($flags & self::HTTP_URL_STRIP_AUTH) {
|
||||
$flags |= self::HTTP_URL_STRIP_USER | self::HTTP_URL_STRIP_PASS;
|
||||
}
|
||||
|
||||
// Schema and host are alwasy replaced
|
||||
foreach (array('scheme', 'host') as $part) {
|
||||
if (isset($parts[$part])) {
|
||||
$url[$part] = $parts[$part];
|
||||
}
|
||||
}
|
||||
|
||||
if ($flags & self::HTTP_URL_REPLACE) {
|
||||
foreach ($keys as $key) {
|
||||
if (isset($parts[$key])) {
|
||||
$url[$key] = $parts[$key];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (isset($parts['path']) && ($flags & self::HTTP_URL_JOIN_PATH)) {
|
||||
if (isset($url['path']) && substr($parts['path'], 0, 1) !== '/') {
|
||||
$url['path'] = rtrim(
|
||||
str_replace(basename($url['path']), '', $url['path']),
|
||||
'/'
|
||||
) . '/' . ltrim($parts['path'], '/');
|
||||
} else {
|
||||
$url['path'] = $parts['path'];
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($parts['query']) && ($flags & self::HTTP_URL_JOIN_QUERY)) {
|
||||
if (isset($url['query'])) {
|
||||
parse_str($url['query'], $url_query);
|
||||
parse_str($parts['query'], $parts_query);
|
||||
|
||||
$url['query'] = http_build_query(
|
||||
array_replace_recursive(
|
||||
$url_query,
|
||||
$parts_query
|
||||
)
|
||||
);
|
||||
} else {
|
||||
$url['query'] = $parts['query'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($url['path']) && substr($url['path'], 0, 1) !== '/') {
|
||||
$url['path'] = '/' . $url['path'];
|
||||
}
|
||||
|
||||
foreach ($keys as $key) {
|
||||
$strip = 'HTTP_URL_STRIP_' . strtoupper($key);
|
||||
if ($flags & constant('utilphp\\util::' . $strip)) {
|
||||
unset($url[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
$parsed_string = '';
|
||||
|
||||
if (isset($url['scheme'])) {
|
||||
$parsed_string .= $url['scheme'] . '://';
|
||||
}
|
||||
|
||||
if (isset($url['user'])) {
|
||||
$parsed_string .= $url['user'];
|
||||
|
||||
if (isset($url['pass'])) {
|
||||
$parsed_string .= ':' . $url['pass'];
|
||||
}
|
||||
|
||||
$parsed_string .= '@';
|
||||
}
|
||||
|
||||
if (isset($url['host'])) {
|
||||
$parsed_string .= $url['host'];
|
||||
}
|
||||
|
||||
if (isset($url['port'])) {
|
||||
$parsed_string .= ':' . $url['port'];
|
||||
}
|
||||
|
||||
if (!empty($url['path'])) {
|
||||
$parsed_string .= $url['path'];
|
||||
} else {
|
||||
$parsed_string .= '/';
|
||||
}
|
||||
|
||||
if (isset($url['query'])) {
|
||||
$parsed_string .= '?' . $url['query'];
|
||||
}
|
||||
|
||||
if (isset($url['fragment'])) {
|
||||
$parsed_string .= '#' . $url['fragment'];
|
||||
}
|
||||
|
||||
$new_url = $url;
|
||||
|
||||
return $parsed_string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts many english words that equate to true or false to boolean.
|
||||
*
|
||||
* Supports 'y', 'n', 'yes', 'no' and a few other variations.
|
||||
*
|
||||
* @param string $string The string to convert to boolean
|
||||
* @param bool $default The value to return if we can't match any
|
||||
* yes/no words
|
||||
* @return boolean
|
||||
*/
|
||||
public static function str_to_bool($string, $default = false)
|
||||
{
|
||||
$yes_words = 'affirmative|all right|aye|indubitably|most assuredly|ok|of course|okay|sure thing|y|yes+|yea|yep|sure|yeah|true|t|on|1|oui|vrai';
|
||||
$no_words = 'no*|no way|nope|nah|na|never|absolutely not|by no means|negative|never ever|false|f|off|0|non|faux';
|
||||
|
||||
if (preg_match('/^(' . $yes_words . ')$/i', $string)) {
|
||||
return true;
|
||||
} elseif (preg_match('/^(' . $no_words . ')$/i', $string)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a string starts with the given string.
|
||||
*
|
||||
* @param string $string
|
||||
* @param string $starts_with
|
||||
* @return boolean
|
||||
*/
|
||||
public static function starts_with($string, $starts_with)
|
||||
{
|
||||
return strpos($string, $starts_with) === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a string ends with the given string.
|
||||
*
|
||||
* @param string $string
|
||||
* @param string $starts_with
|
||||
* @return boolean
|
||||
*/
|
||||
public static function ends_with($string, $ends_with)
|
||||
{
|
||||
return substr($string, -strlen($ends_with)) === $ends_with;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a string contains another string.
|
||||
*
|
||||
* @param string $haystack
|
||||
* @param string $needle
|
||||
* @return boolean
|
||||
*/
|
||||
public static function str_contains($haystack, $needle)
|
||||
{
|
||||
return strpos($haystack, $needle) !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a string contains another string. This version is case
|
||||
* insensitive.
|
||||
*
|
||||
* @param string $haystack
|
||||
* @param string $needle
|
||||
* @return boolean
|
||||
*/
|
||||
public static function str_icontains($haystack, $needle)
|
||||
{
|
||||
return stripos($haystack, $needle) !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the file extension of the given filename.
|
||||
*
|
||||
* @param string $filename
|
||||
* @return string
|
||||
*/
|
||||
public static function get_file_ext($filename)
|
||||
{
|
||||
return pathinfo($filename, PATHINFO_EXTENSION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a directory (and its contents) recursively.
|
||||
*
|
||||
* Contributed by Askar (ARACOOL) <https://github.com/ARACOOOL>
|
||||
*
|
||||
* @param string $dir The directory to be deleted recursively
|
||||
* @param bool $traverseSymlinks Delete contents of symlinks recursively
|
||||
* @return bool
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public static function rmdir($dir, $traverseSymlinks = false)
|
||||
{
|
||||
if (!file_exists($dir)) {
|
||||
return true;
|
||||
} elseif (!is_dir($dir)) {
|
||||
throw new \RuntimeException('Given path is not a directory');
|
||||
}
|
||||
|
||||
if (!is_link($dir) || $traverseSymlinks) {
|
||||
foreach (scandir($dir) as $file) {
|
||||
if ($file === '.' || $file === '..') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$currentPath = $dir . '/' . $file;
|
||||
|
||||
if (is_dir($currentPath)) {
|
||||
self::rmdir($currentPath, $traverseSymlinks);
|
||||
} elseif (!unlink($currentPath)) {
|
||||
// @codeCoverageIgnoreStart
|
||||
throw new \RuntimeException('Unable to delete ' . $currentPath);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Windows treats removing directory symlinks identically to removing directories.
|
||||
if (is_link($dir) && !defined('PHP_WINDOWS_VERSION_MAJOR')) {
|
||||
if (!unlink($dir)) {
|
||||
// @codeCoverageIgnoreStart
|
||||
throw new \RuntimeException('Unable to delete ' . $dir);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
} else {
|
||||
if (!rmdir($dir)) {
|
||||
// @codeCoverageIgnoreStart
|
||||
throw new \RuntimeException('Unable to delete ' . $dir);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert entities, while preserving already-encoded entities.
|
||||
*
|
||||
* @param string $string The text to be converted
|
||||
* @return string
|
||||
*/
|
||||
public static function htmlentities($string, $preserve_encoded_entities = false)
|
||||
{
|
||||
if ($preserve_encoded_entities) {
|
||||
// @codeCoverageIgnoreStart
|
||||
if (defined('HHVM_VERSION')) {
|
||||
$translation_table = get_html_translation_table(HTML_ENTITIES, ENT_QUOTES);
|
||||
} else {
|
||||
$translation_table = get_html_translation_table(HTML_ENTITIES, ENT_QUOTES, self::mbInternalEncoding());
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
$translation_table[chr(38)] = '&';
|
||||
return preg_replace('/&(?![A-Za-z]{0,4}\w{2,3};|#[0-9]{2,3};)/', '&', strtr($string, $translation_table));
|
||||
}
|
||||
|
||||
return htmlentities($string, ENT_QUOTES, self::mbInternalEncoding());
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert >, <, ', " and & to html entities, but preserves entities that
|
||||
* are already encoded.
|
||||
*
|
||||
* @param string $string The text to be converted
|
||||
* @return string
|
||||
*/
|
||||
public static function htmlspecialchars($string, $preserve_encoded_entities = false)
|
||||
{
|
||||
if ($preserve_encoded_entities) {
|
||||
// @codeCoverageIgnoreStart
|
||||
if (defined('HHVM_VERSION')) {
|
||||
$translation_table = get_html_translation_table(HTML_SPECIALCHARS, ENT_QUOTES);
|
||||
} else {
|
||||
$translation_table = get_html_translation_table(HTML_SPECIALCHARS, ENT_QUOTES, self::mbInternalEncoding());
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
$translation_table[chr(38)] = '&';
|
||||
|
||||
return preg_replace('/&(?![A-Za-z]{0,4}\w{2,3};|#[0-9]{2,3};)/', '&', strtr($string, $translation_table));
|
||||
}
|
||||
|
||||
return htmlentities($string, ENT_QUOTES, self::mbInternalEncoding());
|
||||
}
|
||||
|
||||
/**
|
||||
* Transliterates characters to their ASCII equivalents.
|
||||
*
|
||||
* Part of the URLify.php Project <https://github.com/jbroadway/urlify/>
|
||||
*
|
||||
* @see https://github.com/jbroadway/urlify/blob/master/URLify.php
|
||||
*
|
||||
* @param string $text Text that might have not-ASCII characters
|
||||
* @param string $language Specifies a priority for a specific language.
|
||||
* @return string Filtered string with replaced "nice" characters
|
||||
*/
|
||||
public static function downcode($text, $language = '')
|
||||
{
|
||||
self::initLanguageMap($language);
|
||||
|
||||
if (self::seems_utf8($text)) {
|
||||
if (preg_match_all(self::$regex, $text, $matches)) {
|
||||
for ($i = 0; $i < count($matches[0]); $i++) {
|
||||
$char = $matches[0][$i];
|
||||
if (isset(self::$map[$char])) {
|
||||
$text = str_replace($char, self::$map[$char], $text);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Not a UTF-8 string so we assume its ISO-8859-1
|
||||
$search = "\x80\x83\x8a\x8e\x9a\x9e\x9f\xa2\xa5\xb5\xc0\xc1\xc2\xc3\xc4\xc5\xc7\xc8\xc9\xca\xcb\xcc\xcd";
|
||||
$search .= "\xce\xcf\xd1\xd2\xd3\xd4\xd5\xd6\xd8\xd9\xda\xdb\xdc\xdd\xe0\xe1\xe2\xe3\xe4\xe5\xe7\xe8\xe9";
|
||||
$search .= "\xea\xeb\xec\xed\xee\xef\xf1\xf2\xf3\xf4\xf5\xf6\xf8\xf9\xfa\xfb\xfc\xfd\xff";
|
||||
$text = strtr($text, $search, 'EfSZszYcYuAAAAAACEEEEIIIINOOOOOOUUUUYaaaaaaceeeeiiiinoooooouuuuyy');
|
||||
|
||||
// These latin characters should be represented by two characters so
|
||||
// we can't use strtr
|
||||
$complexSearch = array("\x8c", "\x9c", "\xc6", "\xd0", "\xde", "\xdf", "\xe6", "\xf0", "\xfe");
|
||||
$complexReplace = array('OE', 'oe', 'AE', 'DH', 'TH', 'ss', 'ae', 'dh', 'th');
|
||||
$text = str_replace($complexSearch, $complexReplace, $text);
|
||||
}
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts all accent characters to ASCII characters.
|
||||
*
|
||||
* If there are no accent characters, then the string given is just
|
||||
* returned.
|
||||
*
|
||||
* @param string $string Text that might have accent characters
|
||||
* @param string $language Specifies a priority for a specific language.
|
||||
* @return string Filtered string with replaced "nice" characters
|
||||
*/
|
||||
public static function remove_accents($string, $language = '')
|
||||
{
|
||||
if (!preg_match('/[\x80-\xff]/', $string)) {
|
||||
return $string;
|
||||
}
|
||||
|
||||
return self::downcode($string, $language);
|
||||
}
|
||||
|
||||
/**
|
||||
* Strip all witespaces from the given string.
|
||||
*
|
||||
* @param string $string The string to strip
|
||||
* @return string
|
||||
*/
|
||||
public static function strip_space($string)
|
||||
{
|
||||
return preg_replace('/\s+/', '', $string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize a string by performing the following operation :
|
||||
* - Remove accents
|
||||
* - Lower the string
|
||||
* - Remove punctuation characters
|
||||
* - Strip whitespaces
|
||||
*
|
||||
* @param string $string the string to sanitize
|
||||
* @return string
|
||||
*/
|
||||
public static function sanitize_string($string)
|
||||
{
|
||||
$string = self::remove_accents($string);
|
||||
$string = strtolower($string);
|
||||
$string = preg_replace('/[^a-zA-Z 0-9]+/', '', $string);
|
||||
$string = self::strip_space($string);
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pads a given string with zeroes on the left.
|
||||
*
|
||||
* @param int $number The number to pad
|
||||
* @param int $length The total length of the desired string
|
||||
* @return string
|
||||
*/
|
||||
public static function zero_pad($number, $length)
|
||||
{
|
||||
return str_pad($number, $length, '0', STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a unix timestamp to a relative time string, such as "3 days ago"
|
||||
* or "2 weeks ago".
|
||||
*
|
||||
* @param int $from The date to use as a starting point
|
||||
* @param int $to The date to compare to, defaults to now
|
||||
* @param string $suffix The string to add to the end, defaults to " ago"
|
||||
* @return string
|
||||
*/
|
||||
public static function human_time_diff($from, $to = '', $as_text = false, $suffix = ' ago')
|
||||
{
|
||||
if ($to == '') {
|
||||
$to = time();
|
||||
}
|
||||
|
||||
$from = new \DateTime(date('Y-m-d H:i:s', $from));
|
||||
$to = new \DateTime(date('Y-m-d H:i:s', $to));
|
||||
$diff = $from->diff($to);
|
||||
|
||||
if ($diff->y > 1) {
|
||||
$text = $diff->y . ' years';
|
||||
} elseif ($diff->y == 1) {
|
||||
$text = '1 year';
|
||||
} elseif ($diff->m > 1) {
|
||||
$text = $diff->m . ' months';
|
||||
} elseif ($diff->m == 1) {
|
||||
$text = '1 month';
|
||||
} elseif ($diff->d > 7) {
|
||||
$text = ceil($diff->d / 7) . ' weeks';
|
||||
} elseif ($diff->d == 7) {
|
||||
$text = '1 week';
|
||||
} elseif ($diff->d > 1) {
|
||||
$text = $diff->d . ' days';
|
||||
} elseif ($diff->d == 1) {
|
||||
$text = '1 day';
|
||||
} elseif ($diff->h > 1) {
|
||||
$text = $diff->h . ' hours';
|
||||
} elseif ($diff->h == 1) {
|
||||
$text = ' 1 hour';
|
||||
} elseif ($diff->i > 1) {
|
||||
$text = $diff->i . ' minutes';
|
||||
} elseif ($diff->i == 1) {
|
||||
$text = '1 minute';
|
||||
} elseif ($diff->s > 1) {
|
||||
$text = $diff->s . ' seconds';
|
||||
} else {
|
||||
$text = '1 second';
|
||||
}
|
||||
|
||||
if ($as_text) {
|
||||
$text = explode(' ', $text, 2);
|
||||
$text = self::number_to_word($text[0]) . ' ' . $text[1];
|
||||
}
|
||||
|
||||
return trim($text) . $suffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a number into the text equivalent. For example, 456 becomes four
|
||||
* hundred and fifty-six.
|
||||
*
|
||||
* Part of the IntToWords Project.
|
||||
*
|
||||
* @param int|float $number The number to convert into text
|
||||
* @return string
|
||||
*/
|
||||
public static function number_to_word($number)
|
||||
{
|
||||
$number = (string) $number;
|
||||
|
||||
if (strpos($number, '.') !== false) {
|
||||
list($number, $decimal) = explode('.', $number);
|
||||
} else {
|
||||
$decimal = false;
|
||||
}
|
||||
|
||||
$output = '';
|
||||
|
||||
if ($number[0] == '-') {
|
||||
$output = 'negative ';
|
||||
$number = ltrim($number, '-');
|
||||
} elseif ($number[0] == '+') {
|
||||
$output = 'positive ';
|
||||
$number = ltrim($number, '+');
|
||||
}
|
||||
|
||||
if ($number[0] == '0') {
|
||||
$output .= 'zero';
|
||||
} else {
|
||||
$length = 19;
|
||||
$number = str_pad($number, 60, '0', STR_PAD_LEFT);
|
||||
$group = rtrim(chunk_split($number, 3, ' '), ' ');
|
||||
$groups = explode(' ', $group);
|
||||
$groups2 = array();
|
||||
|
||||
foreach ($groups as $group) {
|
||||
$group[1] = isset($group[1]) ? $group[1] : null;
|
||||
$group[2] = isset($group[2]) ? $group[2] : null;
|
||||
$groups2[] = self::numberToWordThreeDigits($group[0], $group[1], $group[2]);
|
||||
}
|
||||
|
||||
for ($z = 0; $z < count($groups2); $z++) {
|
||||
if ($groups2[$z] != '') {
|
||||
$output .= $groups2[$z] . self::numberToWordConvertGroup($length - $z);
|
||||
$output .= ($z < $length && ! array_search('', array_slice($groups2, $z + 1, -1)) && $groups2[$length] != '' && $groups[$length][0] == '0' ? ' and ' : ', ');
|
||||
}
|
||||
}
|
||||
|
||||
$output = rtrim($output, ', ');
|
||||
}
|
||||
|
||||
if ($decimal > 0) {
|
||||
$output .= ' point';
|
||||
|
||||
for ($i = 0; $i < strlen($decimal); $i++) {
|
||||
$output .= ' ' . self::numberToWordConvertDigit($decimal[$i]);
|
||||
}
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
protected static function numberToWordConvertGroup($index)
|
||||
{
|
||||
switch($index) {
|
||||
case 11:
|
||||
return ' decillion';
|
||||
case 10:
|
||||
return ' nonillion';
|
||||
case 9:
|
||||
return ' octillion';
|
||||
case 8:
|
||||
return ' septillion';
|
||||
case 7:
|
||||
return ' sextillion';
|
||||
case 6:
|
||||
return ' quintrillion';
|
||||
case 5:
|
||||
return ' quadrillion';
|
||||
case 4:
|
||||
return ' trillion';
|
||||
case 3:
|
||||
return ' billion';
|
||||
case 2:
|
||||
return ' million';
|
||||
case 1:
|
||||
return ' thousand';
|
||||
case 0:
|
||||
return '';
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
protected static function numberToWordThreeDigits($digit1, $digit2, $digit3)
|
||||
{
|
||||
$output = '';
|
||||
|
||||
if ($digit1 == '0' && $digit2 == '0' && $digit3 == '0') {
|
||||
return '';
|
||||
}
|
||||
|
||||
if ($digit1 != '0') {
|
||||
$output .= self::numberToWordConvertDigit($digit1) . ' hundred';
|
||||
|
||||
if ($digit2 != '0' || $digit3 != '0') {
|
||||
$output .= ' and ';
|
||||
}
|
||||
}
|
||||
if ($digit2 != '0') {
|
||||
$output .= self::numberToWordTwoDigits($digit2, $digit3);
|
||||
} elseif ($digit3 != '0') {
|
||||
$output .= self::numberToWordConvertDigit($digit3);
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
protected static function numberToWordTwoDigits($digit1, $digit2)
|
||||
{
|
||||
if ($digit2 == '0') {
|
||||
switch ($digit1) {
|
||||
case '1':
|
||||
return 'ten';
|
||||
case '2':
|
||||
return 'twenty';
|
||||
case '3':
|
||||
return 'thirty';
|
||||
case '4':
|
||||
return 'forty';
|
||||
case '5':
|
||||
return 'fifty';
|
||||
case '6':
|
||||
return 'sixty';
|
||||
case '7':
|
||||
return 'seventy';
|
||||
case '8':
|
||||
return 'eighty';
|
||||
case '9':
|
||||
return 'ninety';
|
||||
}
|
||||
} elseif ($digit1 == '1') {
|
||||
switch ($digit2) {
|
||||
case '1':
|
||||
return 'eleven';
|
||||
case '2':
|
||||
return 'twelve';
|
||||
case '3':
|
||||
return 'thirteen';
|
||||
case '4':
|
||||
return 'fourteen';
|
||||
case '5':
|
||||
return 'fifteen';
|
||||
case '6':
|
||||
return 'sixteen';
|
||||
case '7':
|
||||
return 'seventeen';
|
||||
case '8':
|
||||
return 'eighteen';
|
||||
case '9':
|
||||
return 'nineteen';
|
||||
}
|
||||
} else {
|
||||
$second_digit = self::numberToWordConvertDigit($digit2);
|
||||
|
||||
switch ($digit1) {
|
||||
case '2':
|
||||
return "twenty-{$second_digit}";
|
||||
case '3':
|
||||
return "thirty-{$second_digit}";
|
||||
case '4':
|
||||
return "forty-{$second_digit}";
|
||||
case '5':
|
||||
return "fifty-{$second_digit}";
|
||||
case '6':
|
||||
return "sixty-{$second_digit}";
|
||||
case '7':
|
||||
return "seventy-{$second_digit}";
|
||||
case '8':
|
||||
return "eighty-{$second_digit}";
|
||||
case '9':
|
||||
return "ninety-{$second_digit}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $digit
|
||||
* @return string
|
||||
* @throws \LogicException
|
||||
*/
|
||||
protected static function numberToWordConvertDigit($digit)
|
||||
{
|
||||
switch ($digit) {
|
||||
case '0':
|
||||
return 'zero';
|
||||
case '1':
|
||||
return 'one';
|
||||
case '2':
|
||||
return 'two';
|
||||
case '3':
|
||||
return 'three';
|
||||
case '4':
|
||||
return 'four';
|
||||
case '5':
|
||||
return 'five';
|
||||
case '6':
|
||||
return 'six';
|
||||
case '7':
|
||||
return 'seven';
|
||||
case '8':
|
||||
return 'eight';
|
||||
case '9':
|
||||
return 'nine';
|
||||
default:
|
||||
throw new \LogicException('Not a number');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Transmit UTF-8 content headers if the headers haven't already been sent.
|
||||
*
|
||||
* @param string $content_type The content type to send out
|
||||
* @return boolean
|
||||
*/
|
||||
public static function utf8_headers($content_type = 'text/html')
|
||||
{
|
||||
// @codeCoverageIgnoreStart
|
||||
if (!headers_sent()) {
|
||||
header('Content-type: ' . $content_type . '; charset=utf-8');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
/**
|
||||
* Transmit headers that force a browser to display the download file
|
||||
* dialog. Cross browser compatible. Only fires if headers have not
|
||||
* already been sent.
|
||||
*
|
||||
* @param string $filename The name of the filename to display to
|
||||
* browsers
|
||||
* @param string $content The content to output for the download.
|
||||
* If you don't specify this, just the
|
||||
* headers will be sent
|
||||
* @return boolean
|
||||
*/
|
||||
public static function force_download($filename, $content = false)
|
||||
{
|
||||
// @codeCoverageIgnoreStart
|
||||
if (!headers_sent()) {
|
||||
// Required for some browsers
|
||||
if (ini_get('zlib.output_compression')) {
|
||||
@ini_set('zlib.output_compression', 'Off');
|
||||
}
|
||||
|
||||
header('Pragma: public');
|
||||
header('Expires: 0');
|
||||
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
|
||||
|
||||
// Required for certain browsers
|
||||
header('Cache-Control: private', false);
|
||||
|
||||
header('Content-Disposition: attachment; filename="' . basename(str_replace('"', '', $filename)) . '";');
|
||||
header('Content-Type: application/force-download');
|
||||
header('Content-Transfer-Encoding: binary');
|
||||
|
||||
if ($content) {
|
||||
header('Content-Length: ' . strlen($content));
|
||||
}
|
||||
|
||||
ob_clean();
|
||||
flush();
|
||||
|
||||
if ($content) {
|
||||
echo $content;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the headers to prevent caching for the different browsers.
|
||||
*
|
||||
* Different browsers support different nocache headers, so several
|
||||
* headers must be sent so that all of them get the point that no
|
||||
* caching should occur
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static function nocache_headers()
|
||||
{
|
||||
// @codeCoverageIgnoreStart
|
||||
if (!headers_sent()) {
|
||||
header('Expires: Wed, 11 Jan 1984 05:00:00 GMT');
|
||||
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
|
||||
header('Cache-Control: no-cache, must-revalidate, max-age=0');
|
||||
header('Pragma: no-cache');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a string of random characters.
|
||||
*
|
||||
* @throws LengthException If $length is bigger than the available
|
||||
* character pool and $no_duplicate_chars is
|
||||
* enabled
|
||||
*
|
||||
* @param integer $length The length of the string to
|
||||
* generate
|
||||
* @param boolean $human_friendly Whether or not to make the
|
||||
* string human friendly by
|
||||
* removing characters that can be
|
||||
* confused with other characters (
|
||||
* O and 0, l and 1, etc)
|
||||
* @param boolean $include_symbols Whether or not to include
|
||||
* symbols in the string. Can not
|
||||
* be enabled if $human_friendly is
|
||||
* true
|
||||
* @param boolean $no_duplicate_chars Whether or not to only use
|
||||
* characters once in the string.
|
||||
* @return string
|
||||
*/
|
||||
public static function random_string($length = 16, $human_friendly = true, $include_symbols = false, $no_duplicate_chars = false)
|
||||
{
|
||||
$nice_chars = 'ABCDEFGHJKLMNPQRSTUVWXYZabcdefhjkmnprstuvwxyz23456789';
|
||||
$all_an = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890';
|
||||
$symbols = '!@#$%^&*()~_-=+{}[]|:;<>,.?/"\'\\`';
|
||||
$string = '';
|
||||
|
||||
// Determine the pool of available characters based on the given parameters
|
||||
if ($human_friendly) {
|
||||
$pool = $nice_chars;
|
||||
} else {
|
||||
$pool = $all_an;
|
||||
|
||||
if ($include_symbols) {
|
||||
$pool .= $symbols;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$no_duplicate_chars) {
|
||||
return substr(str_shuffle(str_repeat($pool, $length)), 0, $length);
|
||||
}
|
||||
|
||||
// Don't allow duplicate letters to be disabled if the length is
|
||||
// longer than the available characters
|
||||
if ($no_duplicate_chars && strlen($pool) < $length) {
|
||||
throw new \LengthException('$length exceeds the size of the pool and $no_duplicate_chars is enabled');
|
||||
}
|
||||
|
||||
// Convert the pool of characters into an array of characters and
|
||||
// shuffle the array
|
||||
$pool = str_split($pool);
|
||||
$poolLength = count($pool);
|
||||
$rand = mt_rand(0, $poolLength - 1);
|
||||
|
||||
// Generate our string
|
||||
for ($i = 0; $i < $length; $i++) {
|
||||
$string .= $pool[$rand];
|
||||
|
||||
// Remove the character from the array to avoid duplicates
|
||||
array_splice($pool, $rand, 1);
|
||||
|
||||
// Generate a new number
|
||||
if (($poolLength - 2 - $i) > 0) {
|
||||
$rand = mt_rand(0, $poolLength - 2 - $i);
|
||||
} else {
|
||||
$rand = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate secure random string of given length
|
||||
* If 'openssl_random_pseudo_bytes' is not available
|
||||
* then generate random string using default function
|
||||
*
|
||||
* Part of the Laravel Project <https://github.com/laravel/laravel>
|
||||
*
|
||||
* @param int $length length of string
|
||||
* @return bool
|
||||
*/
|
||||
public static function secure_random_string($length = 16)
|
||||
{
|
||||
if (function_exists('openssl_random_pseudo_bytes')) {
|
||||
$bytes = openssl_random_pseudo_bytes($length * 2);
|
||||
|
||||
if ($bytes === false) {
|
||||
throw new \LengthException('$length is not accurate, unable to generate random string');
|
||||
}
|
||||
|
||||
return substr(str_replace(array('/', '+', '='), '', base64_encode($bytes)), 0, $length);
|
||||
}
|
||||
|
||||
// @codeCoverageIgnoreStart
|
||||
return static::random_string($length);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given string matches a given pattern.
|
||||
*
|
||||
* Contributed by Abhimanyu Sharma <https://github.com/abhimanyusharma003>
|
||||
*
|
||||
* @param string $pattern Parttern of string exptected
|
||||
* @param string $string String that need to be matched
|
||||
* @return bool
|
||||
*/
|
||||
public static function match_string($pattern, $string, $caseSensitive = true)
|
||||
{
|
||||
if ($pattern == $string) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Preg flags
|
||||
$flags = $caseSensitive ? '' : 'i';
|
||||
|
||||
// Escape any regex special characters
|
||||
$pattern = preg_quote($pattern, '#');
|
||||
|
||||
// Unescape * which is our wildcard character and change it to .*
|
||||
$pattern = str_replace('\*', '.*', $pattern);
|
||||
|
||||
return (bool) preg_match('#^' . $pattern . '$#' . $flags, $string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate an email address.
|
||||
*
|
||||
* @param string $possible_email An email address to validate
|
||||
* @return bool
|
||||
*/
|
||||
public static function validate_email($possible_email)
|
||||
{
|
||||
return (bool) filter_var($possible_email, FILTER_VALIDATE_EMAIL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the URL to a user's gravatar.
|
||||
*
|
||||
* @param string $email The email of the user
|
||||
* @param integer $size The size of the gravatar
|
||||
* @return string
|
||||
*/
|
||||
public static function get_gravatar($email, $size = 32)
|
||||
{
|
||||
if (self::is_https()) {
|
||||
$url = 'https://secure.gravatar.com/';
|
||||
} else {
|
||||
$url = 'http://www.gravatar.com/';
|
||||
}
|
||||
|
||||
$url .= 'avatar/' . md5($email) . '?s=' . (int) abs($size);
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns all of the links in a string into HTML links.
|
||||
*
|
||||
* Part of the LinkifyURL Project <https://github.com/jmrware/LinkifyURL>
|
||||
*
|
||||
* @param string $text The string to parse
|
||||
* @return string
|
||||
*/
|
||||
public static function linkify($text)
|
||||
{
|
||||
$text = preg_replace('/'/', ''', $text); // IE does not handle ' entity!
|
||||
$section_html_pattern = '%# Rev:20100913_0900 github.com/jmrware/LinkifyURL
|
||||
# Section text into HTML <A> tags and everything else.
|
||||
( # $1: Everything not HTML <A> tag.
|
||||
[^<]+(?:(?!<a\b)<[^<]*)* # non A tag stuff starting with non-"<".
|
||||
| (?:(?!<a\b)<[^<]*)+ # non A tag stuff starting with "<".
|
||||
) # End $1.
|
||||
| ( # $2: HTML <A...>...</A> tag.
|
||||
<a\b[^>]*> # <A...> opening tag.
|
||||
[^<]*(?:(?!</a\b)<[^<]*)* # A tag contents.
|
||||
</a\s*> # </A> closing tag.
|
||||
) # End $2:
|
||||
%ix';
|
||||
|
||||
return preg_replace_callback($section_html_pattern, array(__CLASS__, 'linkifyCallback'), $text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for the preg_replace in the linkify() method.
|
||||
*
|
||||
* Part of the LinkifyURL Project <https://github.com/jmrware/LinkifyURL>
|
||||
*
|
||||
* @param array $matches Matches from the preg_ function
|
||||
* @return string
|
||||
*/
|
||||
protected static function linkifyRegex($text)
|
||||
{
|
||||
$url_pattern = '/# Rev:20100913_0900 github.com\/jmrware\/LinkifyURL
|
||||
# Match http & ftp URL that is not already linkified.
|
||||
# Alternative 1: URL delimited by (parentheses).
|
||||
(\() # $1 "(" start delimiter.
|
||||
((?:ht|f)tps?:\/\/[a-z0-9\-._~!$&\'()*+,;=:\/?#[\]@%]+) # $2: URL.
|
||||
(\)) # $3: ")" end delimiter.
|
||||
| # Alternative 2: URL delimited by [square brackets].
|
||||
(\[) # $4: "[" start delimiter.
|
||||
((?:ht|f)tps?:\/\/[a-z0-9\-._~!$&\'()*+,;=:\/?#[\]@%]+) # $5: URL.
|
||||
(\]) # $6: "]" end delimiter.
|
||||
| # Alternative 3: URL delimited by {curly braces}.
|
||||
(\{) # $7: "{" start delimiter.
|
||||
((?:ht|f)tps?:\/\/[a-z0-9\-._~!$&\'()*+,;=:\/?#[\]@%]+) # $8: URL.
|
||||
(\}) # $9: "}" end delimiter.
|
||||
| # Alternative 4: URL delimited by <angle brackets>.
|
||||
(<|&(?:lt|\#60|\#x3c);) # $10: "<" start delimiter (or HTML entity).
|
||||
((?:ht|f)tps?:\/\/[a-z0-9\-._~!$&\'()*+,;=:\/?#[\]@%]+) # $11: URL.
|
||||
(>|&(?:gt|\#62|\#x3e);) # $12: ">" end delimiter (or HTML entity).
|
||||
| # Alternative 5: URL not delimited by (), [], {} or <>.
|
||||
(# $13: Prefix proving URL not already linked.
|
||||
(?: ^ # Can be a beginning of line or string, or
|
||||
| [^=\s\'"\]] # a non-"=", non-quote, non-"]", followed by
|
||||
) \s*[\'"]? # optional whitespace and optional quote;
|
||||
| [^=\s]\s+ # or... a non-equals sign followed by whitespace.
|
||||
) # End $13. Non-prelinkified-proof prefix.
|
||||
(\b # $14: Other non-delimited URL.
|
||||
(?:ht|f)tps?:\/\/ # Required literal http, https, ftp or ftps prefix.
|
||||
[a-z0-9\-._~!$\'()*+,;=:\/?#[\]@%]+ # All URI chars except "&" (normal*).
|
||||
(?: # Either on a "&" or at the end of URI.
|
||||
(?! # Allow a "&" char only if not start of an...
|
||||
&(?:gt|\#0*62|\#x0*3e); # HTML ">" entity, or
|
||||
| &(?:amp|apos|quot|\#0*3[49]|\#x0*2[27]); # a [&\'"] entity if
|
||||
[.!&\',:?;]? # followed by optional punctuation then
|
||||
(?:[^a-z0-9\-._~!$&\'()*+,;=:\/?#[\]@%]|$) # a non-URI char or EOS.
|
||||
) & # If neg-assertion true, match "&" (special).
|
||||
[a-z0-9\-._~!$\'()*+,;=:\/?#[\]@%]* # More non-& URI chars (normal*).
|
||||
)* # Unroll-the-loop (special normal*)*.
|
||||
[a-z0-9\-_~$()*+=\/#[\]@%] # Last char can\'t be [.!&\',;:?]
|
||||
) # End $14. Other non-delimited URL.
|
||||
/imx';
|
||||
|
||||
$url_replace = '$1$4$7$10$13<a href="$2$5$8$11$14">$2$5$8$11$14</a>$3$6$9$12';
|
||||
|
||||
return preg_replace($url_pattern, $url_replace, $text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for the preg_replace in the linkify() method.
|
||||
*
|
||||
* Part of the LinkifyURL Project <https://github.com/jmrware/LinkifyURL>
|
||||
*
|
||||
* @param array $matches Matches from the preg_ function
|
||||
* @return string
|
||||
*/
|
||||
protected static function linkifyCallback($matches)
|
||||
{
|
||||
if (isset($matches[2])) {
|
||||
return $matches[2];
|
||||
}
|
||||
|
||||
return self::linkifyRegex($matches[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current URL.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_current_url()
|
||||
{
|
||||
$url = '';
|
||||
|
||||
// Check to see if it's over https
|
||||
$is_https = self::is_https();
|
||||
if ($is_https) {
|
||||
$url .= 'https://';
|
||||
} else {
|
||||
$url .= 'http://';
|
||||
}
|
||||
|
||||
// Was a username or password passed?
|
||||
if (isset($_SERVER['PHP_AUTH_USER'])) {
|
||||
$url .= $_SERVER['PHP_AUTH_USER'];
|
||||
|
||||
if (isset($_SERVER['PHP_AUTH_PW'])) {
|
||||
$url .= ':' . $_SERVER['PHP_AUTH_PW'];
|
||||
}
|
||||
|
||||
$url .= '@';
|
||||
}
|
||||
|
||||
|
||||
// We want the user to stay on the same host they are currently on,
|
||||
// but beware of security issues
|
||||
// see http://shiflett.org/blog/2006/mar/server-name-versus-http-host
|
||||
$url .= $_SERVER['HTTP_HOST'];
|
||||
|
||||
$port = $_SERVER['SERVER_PORT'];
|
||||
|
||||
// Is it on a non standard port?
|
||||
if ($is_https && ($port != 443)) {
|
||||
$url .= ':' . $_SERVER['SERVER_PORT'];
|
||||
} elseif (!$is_https && ($port != 80)) {
|
||||
$url .= ':' . $_SERVER['SERVER_PORT'];
|
||||
}
|
||||
|
||||
// Get the rest of the URL
|
||||
if (!isset($_SERVER['REQUEST_URI'])) {
|
||||
// Microsoft IIS doesn't set REQUEST_URI by default
|
||||
$url .= $_SERVER['PHP_SELF'];
|
||||
|
||||
if (isset($_SERVER['QUERY_STRING'])) {
|
||||
$url .= '?' . $_SERVER['QUERY_STRING'];
|
||||
}
|
||||
} else {
|
||||
$url .= $_SERVER['REQUEST_URI'];
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the IP address of the client.
|
||||
*
|
||||
* @param boolean $trust_proxy_headers Whether or not to trust the
|
||||
* proxy headers HTTP_CLIENT_IP
|
||||
* and HTTP_X_FORWARDED_FOR. ONLY
|
||||
* use if your server is behind a
|
||||
* proxy that sets these values
|
||||
* @return string
|
||||
*/
|
||||
public static function get_client_ip($trust_proxy_headers = false)
|
||||
{
|
||||
if (!$trust_proxy_headers) {
|
||||
return $_SERVER['REMOTE_ADDR'];
|
||||
}
|
||||
|
||||
if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
|
||||
$ip = $_SERVER['HTTP_CLIENT_IP'];
|
||||
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
|
||||
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
|
||||
} else {
|
||||
$ip = $_SERVER['REMOTE_ADDR'];
|
||||
}
|
||||
|
||||
return $ip;
|
||||
}
|
||||
|
||||
/**
|
||||
* Truncate a string to a specified length without cutting a word off.
|
||||
*
|
||||
* @param string $string The string to truncate
|
||||
* @param integer $length The length to truncate the string to
|
||||
* @param string $append Text to append to the string IF it gets
|
||||
* truncated, defaults to '...'
|
||||
* @return string
|
||||
*/
|
||||
public static function safe_truncate($string, $length, $append = '...')
|
||||
{
|
||||
$ret = substr($string, 0, $length);
|
||||
$last_space = strrpos($ret, ' ');
|
||||
|
||||
if ($last_space !== false && $string != $ret) {
|
||||
$ret = substr($ret, 0, $last_space);
|
||||
}
|
||||
|
||||
if ($ret != $string) {
|
||||
$ret .= $append;
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Truncate the string to given length of charactes.
|
||||
*
|
||||
* @param $string
|
||||
* @param $limit
|
||||
* @param string $append
|
||||
* @return string
|
||||
*/
|
||||
public static function limit_characters($string, $limit = 100, $append = '...')
|
||||
{
|
||||
if (mb_strlen($string) <= $limit) {
|
||||
return $string;
|
||||
}
|
||||
|
||||
return rtrim(mb_substr($string, 0, $limit, 'UTF-8')) . $append;
|
||||
}
|
||||
|
||||
/**
|
||||
* Truncate the string to given length of words.
|
||||
*
|
||||
* @param $string
|
||||
* @param $limit
|
||||
* @param string $append
|
||||
* @return string
|
||||
*/
|
||||
public static function limit_words($string, $limit = 100, $append = '...')
|
||||
{
|
||||
preg_match('/^\s*+(?:\S++\s*+){1,' . $limit . '}/u', $string, $matches);
|
||||
|
||||
if (!isset($matches[0]) || strlen($string) === strlen($matches[0])) {
|
||||
return $string;
|
||||
}
|
||||
|
||||
return rtrim($matches[0]).$append;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ordinal version of a number (appends th, st, nd, rd).
|
||||
*
|
||||
* @param string $number The number to append an ordinal suffix to
|
||||
* @return string
|
||||
*/
|
||||
public static function ordinal($number)
|
||||
{
|
||||
$test_c = abs($number) % 10;
|
||||
$ext = ((abs($number) % 100 < 21 && abs($number) % 100 > 4) ? 'th' : (($test_c < 4) ? ($test_c < 3) ? ($test_c < 2) ? ($test_c < 1) ? 'th' : 'st' : 'nd' : 'rd' : 'th'));
|
||||
|
||||
return $number . $ext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file permissions as a nice string, like -rw-r--r-- or false
|
||||
* if the file is not found.
|
||||
*
|
||||
* @param string $file The name of the file to get permissions form
|
||||
* @param int $perms Numerical value of permissions to display as text.
|
||||
* @return string
|
||||
*/
|
||||
public static function full_permissions($file, $perms = null)
|
||||
{
|
||||
if (is_null($perms)) {
|
||||
if (!file_exists($file)) {
|
||||
return false;
|
||||
}
|
||||
$perms = fileperms($file);
|
||||
}
|
||||
|
||||
if (($perms & 0xC000) == 0xC000) {
|
||||
// Socket
|
||||
$info = 's';
|
||||
} elseif (($perms & 0xA000) == 0xA000) {
|
||||
// Symbolic Link
|
||||
$info = 'l';
|
||||
} elseif (($perms & 0x8000) == 0x8000) {
|
||||
// Regular
|
||||
$info = '-';
|
||||
} elseif (($perms & 0x6000) == 0x6000) {
|
||||
// Block special
|
||||
$info = 'b';
|
||||
} elseif (($perms & 0x4000) == 0x4000) {
|
||||
// Directory
|
||||
$info = 'd';
|
||||
} elseif (($perms & 0x2000) == 0x2000) {
|
||||
// Character special
|
||||
$info = 'c';
|
||||
} elseif (($perms & 0x1000) == 0x1000) {
|
||||
// FIFO pipe
|
||||
$info = 'p';
|
||||
} else {
|
||||
// Unknown
|
||||
$info = 'u';
|
||||
}
|
||||
|
||||
// Owner
|
||||
$info .= (($perms & 0x0100) ? 'r' : '-');
|
||||
$info .= (($perms & 0x0080) ? 'w' : '-');
|
||||
$info .= (($perms & 0x0040) ?
|
||||
(($perms & 0x0800) ? 's' : 'x') :
|
||||
(($perms & 0x0800) ? 'S' : '-'));
|
||||
|
||||
// Group
|
||||
$info .= (($perms & 0x0020) ? 'r' : '-');
|
||||
$info .= (($perms & 0x0010) ? 'w' : '-');
|
||||
$info .= (($perms & 0x0008) ?
|
||||
(($perms & 0x0400) ? 's' : 'x') :
|
||||
(($perms & 0x0400) ? 'S' : '-'));
|
||||
|
||||
// World
|
||||
$info .= (($perms & 0x0004) ? 'r' : '-');
|
||||
$info .= (($perms & 0x0002) ? 'w' : '-');
|
||||
$info .= (($perms & 0x0001) ?
|
||||
(($perms & 0x0200) ? 't' : 'x') :
|
||||
(($perms & 0x0200) ? 'T' : '-'));
|
||||
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first element in an array.
|
||||
*
|
||||
* @param array $array
|
||||
* @return mixed
|
||||
*/
|
||||
public static function array_first(array $array)
|
||||
{
|
||||
return reset($array);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last element in an array.
|
||||
*
|
||||
* @param array $array
|
||||
* @return mixed
|
||||
*/
|
||||
public static function array_last(array $array)
|
||||
{
|
||||
return end($array);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first key in an array.
|
||||
*
|
||||
* @param array $array
|
||||
* @return int|string
|
||||
*/
|
||||
public static function array_first_key(array $array)
|
||||
{
|
||||
reset($array);
|
||||
|
||||
return key($array);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last key in an array.
|
||||
*
|
||||
* @param array $array
|
||||
* @return int|string
|
||||
*/
|
||||
public static function array_last_key(array $array)
|
||||
{
|
||||
end($array);
|
||||
|
||||
return key($array);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flatten a multi-dimensional array into a one dimensional array.
|
||||
*
|
||||
* Contributed by Theodore R. Smith of PHP Experts, Inc. <http://www.phpexperts.pro/>
|
||||
*
|
||||
* @param array $array The array to flatten
|
||||
* @param boolean $preserve_keys Whether or not to preserve array keys.
|
||||
* Keys from deeply nested arrays will
|
||||
* overwrite keys from shallowy nested arrays
|
||||
* @return array
|
||||
*/
|
||||
public static function array_flatten(array $array, $preserve_keys = true)
|
||||
{
|
||||
$flattened = array();
|
||||
|
||||
array_walk_recursive($array, function($value, $key) use (&$flattened, $preserve_keys) {
|
||||
if ($preserve_keys && !is_int($key)) {
|
||||
$flattened[$key] = $value;
|
||||
} else {
|
||||
$flattened[] = $value;
|
||||
}
|
||||
});
|
||||
|
||||
return $flattened;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts an array, and returns an array of values from that array as
|
||||
* specified by $field. For example, if the array is full of objects
|
||||
* and you call util::array_pluck($array, 'name'), the function will
|
||||
* return an array of values from $array[]->name.
|
||||
*
|
||||
* @param array $array An array
|
||||
* @param string $field The field to get values from
|
||||
* @param boolean $preserve_keys Whether or not to preserve the
|
||||
* array keys
|
||||
* @param boolean $remove_nomatches If the field doesn't appear to be set,
|
||||
* remove it from the array
|
||||
* @return array
|
||||
*/
|
||||
public static function array_pluck(array $array, $field, $preserve_keys = true, $remove_nomatches = true)
|
||||
{
|
||||
$new_list = array();
|
||||
|
||||
foreach ($array as $key => $value) {
|
||||
if (is_object($value)) {
|
||||
if (isset($value->{$field})) {
|
||||
if ($preserve_keys) {
|
||||
$new_list[$key] = $value->{$field};
|
||||
} else {
|
||||
$new_list[] = $value->{$field};
|
||||
}
|
||||
} elseif (!$remove_nomatches) {
|
||||
$new_list[$key] = $value;
|
||||
}
|
||||
} else {
|
||||
if (isset($value[$field])) {
|
||||
if ($preserve_keys) {
|
||||
$new_list[$key] = $value[$field];
|
||||
} else {
|
||||
$new_list[] = $value[$field];
|
||||
}
|
||||
} elseif (!$remove_nomatches) {
|
||||
$new_list[$key] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $new_list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for a given value in an array of arrays, objects and scalar
|
||||
* values. You can optionally specify a field of the nested arrays and
|
||||
* objects to search in.
|
||||
*
|
||||
* @param array $array The array to search
|
||||
* @param scalar $search The value to search for
|
||||
* @param string $field The field to search in, if not specified
|
||||
* all fields will be searched
|
||||
* @return boolean|scalar False on failure or the array key on success
|
||||
*/
|
||||
public static function array_search_deep(array $array, $search, $field = false)
|
||||
{
|
||||
// *grumbles* stupid PHP type system
|
||||
$search = (string) $search;
|
||||
|
||||
foreach ($array as $key => $elem) {
|
||||
// *grumbles* stupid PHP type system
|
||||
$key = (string) $key;
|
||||
|
||||
if ($field) {
|
||||
if (is_object($elem) && $elem->{$field} === $search) {
|
||||
return $key;
|
||||
} elseif (is_array($elem) && $elem[$field] === $search) {
|
||||
return $key;
|
||||
} elseif (is_scalar($elem) && $elem === $search) {
|
||||
return $key;
|
||||
}
|
||||
} else {
|
||||
if (is_object($elem)) {
|
||||
$elem = (array) $elem;
|
||||
|
||||
if (in_array($search, $elem)) {
|
||||
return $key;
|
||||
}
|
||||
} elseif (is_array($elem) && in_array($search, $elem)) {
|
||||
return $key;
|
||||
} elseif (is_scalar($elem) && $elem === $search) {
|
||||
return $key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array containing all the elements of arr1 after applying
|
||||
* the callback function to each one.
|
||||
*
|
||||
* @param string $callback Callback function to run for each
|
||||
* element in each array
|
||||
* @param array $array An array to run through the callback
|
||||
* function
|
||||
* @param boolean $on_nonscalar Whether or not to call the callback
|
||||
* function on nonscalar values
|
||||
* (Objects, resources, etc)
|
||||
* @return array
|
||||
*/
|
||||
public static function array_map_deep(array $array, $callback, $on_nonscalar = false)
|
||||
{
|
||||
foreach ($array as $key => $value) {
|
||||
if (is_array($value)) {
|
||||
$args = array($value, $callback, $on_nonscalar);
|
||||
$array[$key] = call_user_func_array(array(__CLASS__, __FUNCTION__), $args);
|
||||
} elseif (is_scalar($value) || $on_nonscalar) {
|
||||
$array[$key] = call_user_func($callback, $value);
|
||||
}
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
public static function array_clean(array $array)
|
||||
{
|
||||
return array_filter($array);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper to prevent errors if the user doesn't have the mbstring
|
||||
* extension installed.
|
||||
*
|
||||
* @param string $encoding
|
||||
* @return string
|
||||
*/
|
||||
protected static function mbInternalEncoding($encoding = null)
|
||||
{
|
||||
if (function_exists('mb_internal_encoding')) {
|
||||
return $encoding ? mb_internal_encoding($encoding) : mb_internal_encoding();
|
||||
}
|
||||
|
||||
// @codeCoverageIgnoreStart
|
||||
return 'UTF-8';
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the writable bit on a file to the minimum value that allows the user
|
||||
* running PHP to write to it.
|
||||
*
|
||||
* @param string $filename The filename to set the writable bit on
|
||||
* @param boolean $writable Whether to make the file writable or not
|
||||
* @return boolean
|
||||
*/
|
||||
public static function set_writable($filename, $writable = true)
|
||||
{
|
||||
$stat = @stat($filename);
|
||||
|
||||
if ($stat === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We're on Windows
|
||||
if (strncasecmp(PHP_OS, 'WIN', 3) === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
list($myuid, $mygid) = array(posix_geteuid(), posix_getgid());
|
||||
|
||||
if ($writable) {
|
||||
// Set only the user writable bit (file is owned by us)
|
||||
if ($stat['uid'] == $myuid) {
|
||||
return chmod($filename, fileperms($filename) | 0200);
|
||||
}
|
||||
|
||||
// Set only the group writable bit (file group is the same as us)
|
||||
if ($stat['gid'] == $mygid) {
|
||||
return chmod($filename, fileperms($filename) | 0220);
|
||||
}
|
||||
|
||||
// Set the world writable bit (file isn't owned or grouped by us)
|
||||
return chmod($filename, fileperms($filename) | 0222);
|
||||
} else {
|
||||
// Set only the user writable bit (file is owned by us)
|
||||
if ($stat['uid'] == $myuid) {
|
||||
return chmod($filename, (fileperms($filename) | 0222) ^ 0222);
|
||||
}
|
||||
|
||||
// Set only the group writable bit (file group is the same as us)
|
||||
if ($stat['gid'] == $mygid) {
|
||||
return chmod($filename, (fileperms($filename) | 0222) ^ 0022);
|
||||
}
|
||||
|
||||
// Set the world writable bit (file isn't owned or grouped by us)
|
||||
return chmod($filename, (fileperms($filename) | 0222) ^ 0002);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the readable bit on a file to the minimum value that allows the user
|
||||
* running PHP to read to it.
|
||||
*
|
||||
* @param string $filename The filename to set the readable bit on
|
||||
* @param boolean $readable Whether to make the file readable or not
|
||||
* @return boolean
|
||||
*/
|
||||
public static function set_readable($filename, $readable = true)
|
||||
{
|
||||
$stat = @stat($filename);
|
||||
|
||||
if ($stat === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We're on Windows
|
||||
if (strncasecmp(PHP_OS, 'WIN', 3) === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
list($myuid, $mygid) = array(posix_geteuid(), posix_getgid());
|
||||
|
||||
if ($readable) {
|
||||
// Set only the user readable bit (file is owned by us)
|
||||
if ($stat['uid'] == $myuid) {
|
||||
return chmod($filename, fileperms($filename) | 0400);
|
||||
}
|
||||
|
||||
// Set only the group readable bit (file group is the same as us)
|
||||
if ($stat['gid'] == $mygid) {
|
||||
return chmod($filename, fileperms($filename) | 0440);
|
||||
}
|
||||
|
||||
// Set the world readable bit (file isn't owned or grouped by us)
|
||||
return chmod($filename, fileperms($filename) | 0444);
|
||||
} else {
|
||||
// Set only the user readable bit (file is owned by us)
|
||||
if ($stat['uid'] == $myuid) {
|
||||
return chmod($filename, (fileperms($filename) | 0444) ^ 0444);
|
||||
}
|
||||
|
||||
// Set only the group readable bit (file group is the same as us)
|
||||
if ($stat['gid'] == $mygid) {
|
||||
return chmod($filename, (fileperms($filename) | 0444) ^ 0044);
|
||||
}
|
||||
|
||||
// Set the world readable bit (file isn't owned or grouped by us)
|
||||
return chmod($filename, (fileperms($filename) | 0444) ^ 0004);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the executable bit on a file to the minimum value that allows the
|
||||
* user running PHP to read to it.
|
||||
*
|
||||
* @param string $filename The filename to set the executable bit on
|
||||
* @param boolean $executable Whether to make the file executable or not
|
||||
* @return boolean
|
||||
*/
|
||||
public static function set_executable($filename, $executable = true)
|
||||
{
|
||||
$stat = @stat($filename);
|
||||
|
||||
if ($stat === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We're on Windows
|
||||
if (strncasecmp(PHP_OS, 'WIN', 3) === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
list($myuid, $mygid) = array(posix_geteuid(), posix_getgid());
|
||||
|
||||
if ($executable) {
|
||||
// Set only the user readable bit (file is owned by us)
|
||||
if ($stat['uid'] == $myuid) {
|
||||
return chmod($filename, fileperms($filename) | 0100);
|
||||
}
|
||||
|
||||
// Set only the group readable bit (file group is the same as us)
|
||||
if ($stat['gid'] == $mygid) {
|
||||
return chmod($filename, fileperms($filename) | 0110);
|
||||
}
|
||||
|
||||
// Set the world readable bit (file isn't owned or grouped by us)
|
||||
return chmod($filename, fileperms($filename) | 0111);
|
||||
} else {
|
||||
// Set only the user readable bit (file is owned by us)
|
||||
if ($stat['uid'] == $myuid) {
|
||||
return chmod($filename, (fileperms($filename) | 0111) ^ 0111);
|
||||
}
|
||||
|
||||
// Set only the group readable bit (file group is the same as us)
|
||||
if ($stat['gid'] == $mygid) {
|
||||
return chmod($filename, (fileperms($filename) | 0111) ^ 0011);
|
||||
}
|
||||
|
||||
// Set the world readable bit (file isn't owned or grouped by us)
|
||||
return chmod($filename, (fileperms($filename) | 0111) ^ 0001);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns size of a given directory in bytes.
|
||||
*
|
||||
* @param string $dir
|
||||
* @return integer
|
||||
*/
|
||||
public static function directory_size($dir)
|
||||
{
|
||||
$size = 0;
|
||||
foreach(new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($dir, \FilesystemIterator::CURRENT_AS_FILEINFO | \FilesystemIterator::SKIP_DOTS)) as $file => $key) {
|
||||
if ($key->isFile()) {
|
||||
$size += $key->getSize();
|
||||
}
|
||||
}
|
||||
return $size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a home directory of current user.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_user_directory()
|
||||
{
|
||||
if (isset($_SERVER['HOMEDRIVE'])) return $_SERVER['HOMEDRIVE'] . $_SERVER['HOMEPATH'];
|
||||
else return $_SERVER['HOME'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all paths inside a directory.
|
||||
*
|
||||
* @param string $dir
|
||||
* @return array
|
||||
*/
|
||||
public static function directory_contents($dir)
|
||||
{
|
||||
$contents = array();
|
||||
foreach(new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($dir, \FilesystemIterator::KEY_AS_PATHNAME | \FilesystemIterator::CURRENT_AS_FILEINFO | \FilesystemIterator::SKIP_DOTS)) as $pathname => $fi) {
|
||||
$contents[] = $pathname;
|
||||
}
|
||||
natsort($contents);
|
||||
return $contents;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
<?php
|
||||
|
||||
require __DIR__ . '/src/utilphp/util.php';
|
||||
|
||||
/**
|
||||
* Globally namespaced version of the class.
|
||||
*
|
||||
* @author Brandon Wamboldt <brandon.wamboldt@gmail.com>
|
||||
*/
|
||||
class util extends \utilphp\util { }
|
||||
Reference in new issue
Block a user