update
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
.idea/
|
||||
vendor/
|
||||
|
||||
error_log
|
||||
composer.lock
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"name": "nightmare/php",
|
||||
"description": "php helper",
|
||||
"require": {
|
||||
"php": ">=7.4.0",
|
||||
"colinodell/json5": ">=2.3",
|
||||
"php-curl-class/php-curl-class": ">=11.0",
|
||||
"symfony/browser-kit": "^5.4 || ^6.4 || ^7.4",
|
||||
"symfony/cache": "^5.4 || ^6.4 || ^7.4",
|
||||
"symfony/css-selector": "^5.4 || ^6.4 || ^7.4",
|
||||
"symfony/http-client": "^5.4 || ^6.4 || ^7.4",
|
||||
"symfony/var-dumper": "^5.4 || ^6.4 || ^7.4",
|
||||
"symfony/yaml": "^5.4 || ^6.4 || ^7.4"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Nightmare\\": "src/"
|
||||
},
|
||||
"files": [
|
||||
"src/function_global.php",
|
||||
"src/function.php"
|
||||
]
|
||||
},
|
||||
"config": {
|
||||
"sort-packages": true,
|
||||
"platform": {
|
||||
"php": "7.4"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
parameters:
|
||||
phpVersion: 70400
|
||||
level: 6
|
||||
paths:
|
||||
- src/
|
||||
reportUnmatchedIgnoredErrors: false
|
||||
ignoreErrors:
|
||||
-
|
||||
identifiers:
|
||||
- missingType.return
|
||||
- missingType.parameter
|
||||
- missingType.iterableValue
|
||||
- missingType.property
|
||||
- property.onlyWritten
|
||||
- missingType.generics
|
||||
- property.unused
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace Nightmare;
|
||||
|
||||
class Arr
|
||||
{
|
||||
/**
|
||||
* @param int $page
|
||||
* @param int $per_page
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
public static function get_by_page($page, $per_page, $data)
|
||||
{
|
||||
$offset = ($page - 1) * $per_page;
|
||||
return array_slice($data, $offset, $per_page);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $filename
|
||||
* @param array $arr
|
||||
* @return int|false
|
||||
*/
|
||||
public static function to_file($filename, $arr) {
|
||||
return file_put_contents(
|
||||
$filename,
|
||||
'<?php return ' . var_export($arr, true) . ';'
|
||||
);
|
||||
}
|
||||
}
|
||||
+207
@@ -0,0 +1,207 @@
|
||||
<?php
|
||||
|
||||
namespace Nightmare;
|
||||
|
||||
class Cache
|
||||
{
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private static $debug = false;
|
||||
|
||||
/**
|
||||
* @var int|null
|
||||
*/
|
||||
private static $expire = null;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private static $prefix = '';
|
||||
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
private static $adapter;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private static $adapters = [];
|
||||
|
||||
// common
|
||||
|
||||
/**
|
||||
* @param bool $debug
|
||||
* @return void
|
||||
*/
|
||||
public static function set_debug($debug)
|
||||
{
|
||||
self::$debug = $debug;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $prefix
|
||||
* @return void
|
||||
*/
|
||||
public static function set_prefix($prefix)
|
||||
{
|
||||
self::$prefix = $prefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int|null $ttl
|
||||
* @return void
|
||||
*/
|
||||
public static function set_expire($ttl = null)
|
||||
{
|
||||
self::$expire = $ttl;
|
||||
}
|
||||
|
||||
// adapter
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @return void
|
||||
*/
|
||||
public static function set_adapter($key)
|
||||
{
|
||||
self::$adapter = self::$adapters[$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @return mixed
|
||||
*/
|
||||
public static function get_adapter($key)
|
||||
{
|
||||
return self::$adapters[$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param mixed $adapter
|
||||
* @return void
|
||||
*/
|
||||
public static function add_adapter($key, $adapter)
|
||||
{
|
||||
self::$adapters = array_merge(self::$adapters, [$key => $adapter]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @return void
|
||||
*/
|
||||
public function remove_adapter($key)
|
||||
{
|
||||
unset(self::$adapters[$key]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function get_adapters()
|
||||
{
|
||||
return self::$adapters;
|
||||
}
|
||||
|
||||
// cache
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @return bool
|
||||
*/
|
||||
public static function has($key)
|
||||
{
|
||||
return self::$adapter->hasItem(self::$prefix . $key);
|
||||
}
|
||||
|
||||
// truyen 1 tham so - lay binh thuong
|
||||
// truyen 2 tham so tro len - luu cache cho lan sau
|
||||
/**
|
||||
* @param string $key
|
||||
* @param mixed $default
|
||||
* @param array $opt
|
||||
* @return mixed
|
||||
*/
|
||||
public static function get($key, $default = null, $opt = [])
|
||||
{
|
||||
$opt += [
|
||||
'expire' => self::$expire,
|
||||
'debug' => false,
|
||||
'save' => true,
|
||||
'save_if' => null, // ?callable
|
||||
];
|
||||
|
||||
if (self::$debug || $opt['debug']) {
|
||||
self::unset(self::$prefix . $key);
|
||||
}
|
||||
|
||||
// get cache
|
||||
$item = self::$adapter->getItem(self::$prefix . $key);
|
||||
|
||||
if ($item->isHit()) {
|
||||
return $item->get();
|
||||
} else {
|
||||
if (is_callable($default)) {
|
||||
$default = call_user_func($default, $opt);
|
||||
}
|
||||
|
||||
if ($opt['save']) {
|
||||
$save = false;
|
||||
|
||||
if (is_callable($opt['save_if'])) {
|
||||
if (call_user_func($opt['save_if'], $default)) {
|
||||
$save = true;
|
||||
}
|
||||
} else {
|
||||
$save = true;
|
||||
}
|
||||
|
||||
if ($save) {
|
||||
self::set($key, $default, $opt['expire']);
|
||||
}
|
||||
}
|
||||
|
||||
return $default;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @param int|null $expire
|
||||
* @return bool
|
||||
*/
|
||||
public static function set($key, $value, $expire = null)
|
||||
{
|
||||
$item = self::$adapter->getItem(self::$prefix . $key);
|
||||
|
||||
if ($expire !== null) {
|
||||
$item->expiresAfter($expire);
|
||||
} elseif (self::$expire !== null) {
|
||||
$item->expiresAfter(self::$expire);
|
||||
}
|
||||
|
||||
$item->set($value);
|
||||
return self::$adapter->save($item);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @return bool
|
||||
*/
|
||||
public static function unset($key)
|
||||
{
|
||||
return self::$adapter->deleteItem(self::$prefix . $key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $prefix
|
||||
* @return bool
|
||||
*/
|
||||
public static function clear($prefix = '')
|
||||
{
|
||||
return self::$adapter->clear($prefix);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Nightmare\Cache\Driver;
|
||||
|
||||
use Nightmare\Fs;
|
||||
|
||||
class File
|
||||
{
|
||||
private $opt;
|
||||
|
||||
public function __construct() {
|
||||
}
|
||||
|
||||
public function has($key) {}
|
||||
public function get($key, $default = null) {}
|
||||
public function set($key, $value, $ttl) {}
|
||||
public function unset($key) {}
|
||||
|
||||
public function clear() {}
|
||||
public function clear_prefix($prefix) {}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
namespace Nightmare;
|
||||
|
||||
class Config
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $config = [];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $file;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $data = [];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $prefix = '';
|
||||
|
||||
/**
|
||||
* @param array $config
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($config)
|
||||
{
|
||||
$this->config = array_merge([
|
||||
'driver' => 'memory'
|
||||
], $config);
|
||||
|
||||
switch ($this->config['driver']) {
|
||||
case 'memory':
|
||||
break;
|
||||
case 'php_file':
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $prefix
|
||||
* @return void
|
||||
*/
|
||||
public function set_prefix($prefix)
|
||||
{
|
||||
$this->prefix = $prefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param mixed $default
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($key, $default = null)
|
||||
{
|
||||
if (file_exists($this->config['file'])) {
|
||||
$this->data = require $this->config['file'];
|
||||
}
|
||||
|
||||
return $this->data[$this->prefix . $key] ?? $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @return void
|
||||
*/
|
||||
public function set($key, $value)
|
||||
{
|
||||
$this->data[$this->prefix . $key] = $value;
|
||||
|
||||
file_put_contents($this->config['file'], '<?php return ' . var_export($this->data, true) . ';');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @return void
|
||||
*/
|
||||
public function remove($key)
|
||||
{
|
||||
unset($this->data[$this->prefix . $key]);
|
||||
|
||||
file_put_contents($this->config['file'], '<?php return ' . var_export($this->data, true) . ';');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace Nightmare\Crypto;
|
||||
|
||||
class Aes256Cbc
|
||||
{
|
||||
public static function get_key($input_key)
|
||||
{
|
||||
return hash('sha256', $input_key, true);
|
||||
}
|
||||
|
||||
public static function encrypt($plaintext, $input_key)
|
||||
{
|
||||
$key = self::get_key($input_key);
|
||||
$iv = openssl_random_pseudo_bytes(16);
|
||||
|
||||
$ciphertext = openssl_encrypt(
|
||||
$plaintext,
|
||||
'AES-256-CBC',
|
||||
$key,
|
||||
OPENSSL_RAW_DATA,
|
||||
$iv
|
||||
);
|
||||
|
||||
$result = base64_encode($iv . $ciphertext);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function decrypt($encrypted_data, $input_key)
|
||||
{
|
||||
$key = self::get_key($input_key);
|
||||
$raw = base64_decode($encrypted_data);
|
||||
$iv = substr($raw, 0, 16);
|
||||
$ciphertext = substr($raw, 16);
|
||||
|
||||
$decrypted = openssl_decrypt(
|
||||
$ciphertext,
|
||||
'AES-256-CBC',
|
||||
$key,
|
||||
OPENSSL_RAW_DATA,
|
||||
$iv
|
||||
);
|
||||
|
||||
return $decrypted;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,248 @@
|
||||
<?php
|
||||
|
||||
namespace Nightmare\Database;
|
||||
|
||||
use PDO;
|
||||
use PDOStatement;
|
||||
|
||||
class Database
|
||||
{
|
||||
/**
|
||||
* @var PDO
|
||||
*/
|
||||
private $driver;
|
||||
|
||||
public function __construct(
|
||||
$dsn,
|
||||
$username = null,
|
||||
$password = null,
|
||||
$options = null
|
||||
) {
|
||||
if ($dsn instanceof PDO) {
|
||||
$this->driver = $dsn;
|
||||
} else {
|
||||
$this->driver = new PDO(
|
||||
$dsn,
|
||||
$username,
|
||||
$password,
|
||||
array_merge([
|
||||
PDO::MYSQL_ATTR_INIT_COMMAND, 'SET sql_mode="ANSI,TRADITIONAL"'
|
||||
], (array) $options)
|
||||
);
|
||||
}
|
||||
|
||||
$this->driver->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
$this->driver->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
|
||||
$this->driver->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_CLASS);
|
||||
$this->driver->setAttribute(PDO::ATTR_STATEMENT_CLASS, [Statement::class]);
|
||||
|
||||
$this->driver->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true);
|
||||
}
|
||||
|
||||
public function driver()
|
||||
{
|
||||
return $this->driver;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sql
|
||||
* @param array|null $params
|
||||
* @return PDOStatement|false
|
||||
*/
|
||||
public function query($sql, $params = null)
|
||||
{
|
||||
$stmt = $this->driver->prepare($sql);
|
||||
$stmt->execute($params);
|
||||
|
||||
return $stmt;
|
||||
}
|
||||
|
||||
/**
|
||||
* giống exec() nhưng dùng prepare
|
||||
*
|
||||
* @param string $sql
|
||||
* @param array|null $params
|
||||
* @return int
|
||||
*/
|
||||
public function query_count($sql, $params = null)
|
||||
{
|
||||
$stmt = self::query($sql, $params);
|
||||
|
||||
return $stmt->rowCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $table
|
||||
* @param array $params
|
||||
* @return string
|
||||
*/
|
||||
public function insert($table, $params)
|
||||
{
|
||||
$sql = 'insert into "' . $table . '"'
|
||||
. ' (' . implode(',', $this->buildName(array_keys($params))) . ')'
|
||||
. ' values (' . implode(',', array_fill(0, count($params), '?')) . ')';
|
||||
//dd($sql);
|
||||
$this->query($sql, array_values($params));
|
||||
|
||||
return $this->driver->lastInsertId();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $table
|
||||
* @param array $con
|
||||
* @param array $arr
|
||||
* @return void
|
||||
*/
|
||||
public function update_or_insert($table, $con, $arr)
|
||||
{
|
||||
$where_conditions = [];
|
||||
$where_params = [];
|
||||
|
||||
foreach ($con as $column => $value) {
|
||||
$where_conditions[] = sprintf('"%s" = ?', $column);
|
||||
$where_params[] = $value;
|
||||
}
|
||||
|
||||
$where_clause = implode(' AND ', $where_conditions);
|
||||
$check_sql = sprintf('SELECT COUNT(*) FROM "%s" WHERE %s', $table, $where_clause);
|
||||
$count = $this->fetch_column($check_sql, $where_params);
|
||||
|
||||
if ($count > 0) {
|
||||
$update_parts = [];
|
||||
$update_params = [];
|
||||
|
||||
foreach ($arr as $column => $value) {
|
||||
$update_parts[] = sprintf('"%s" = ?', $column);
|
||||
$update_params[] = $value;
|
||||
}
|
||||
|
||||
$update_clause = implode(', ', $update_parts);
|
||||
$update_sql = sprintf('UPDATE "%s" SET %s WHERE %s', $table, $update_clause, $where_clause);
|
||||
|
||||
$this->query($update_sql, array_merge($update_params, $where_params));
|
||||
} else {
|
||||
$this->insert($table, array_merge($con, $arr));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sql
|
||||
* @param array|null $params
|
||||
* @return int
|
||||
*/
|
||||
public function update($sql, $params = null)
|
||||
{
|
||||
$stmt = $this->query($sql, $params);
|
||||
return $stmt->rowCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sql
|
||||
* @param array|null $params
|
||||
* @return mixed
|
||||
*/
|
||||
public function fetch($sql, $params = null)
|
||||
{
|
||||
return $this->query($sql, $params)->fetch();
|
||||
}
|
||||
|
||||
public function exec($sql)
|
||||
{
|
||||
return $this->driver->exec($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sql
|
||||
* @param array|null $params
|
||||
* @return array
|
||||
*/
|
||||
public function fetchAll($sql, $params = null)
|
||||
{
|
||||
return $this->query($sql, $params)->fetchAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sql
|
||||
* @param array|null $params
|
||||
* @return array
|
||||
*/
|
||||
public function fetch_all($sql, $params = null)
|
||||
{
|
||||
return $this->query($sql, $params)->fetchAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sql
|
||||
* @param array|null $params
|
||||
* @param int $column
|
||||
* @return mixed
|
||||
*/
|
||||
public function fetchColumn($sql, $params = null, $column = 0)
|
||||
{
|
||||
$stmt = $this->query($sql, $params);
|
||||
return $stmt->fetchColumn($column);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sql
|
||||
* @param array|null $params
|
||||
* @param int $column
|
||||
* @return mixed
|
||||
*/
|
||||
public function fetch_column($sql, $params = null, $column = 0)
|
||||
{
|
||||
$stmt = $this->query($sql, $params);
|
||||
return $stmt->fetchColumn($column);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $page
|
||||
* @param int $per_page
|
||||
* @return int
|
||||
*/
|
||||
public function getOffset($page, $per_page)
|
||||
{
|
||||
return $page * $per_page - $per_page;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $page
|
||||
* @param int $per_page
|
||||
* @return int
|
||||
*/
|
||||
public function get_offset($page, $per_page)
|
||||
{
|
||||
return $page * $per_page - $per_page;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $str
|
||||
* @return string
|
||||
*/
|
||||
public function quote($str)
|
||||
{
|
||||
return $this->driver->quote($str);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $arr
|
||||
* @return array
|
||||
*/
|
||||
public function buildName($arr)
|
||||
{
|
||||
return array_map(function ($item) {
|
||||
return '"' . $item . '"';
|
||||
}, $arr);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $arr
|
||||
* @return array
|
||||
*/
|
||||
public function build_name($arr)
|
||||
{
|
||||
return array_map(function ($item) {
|
||||
return '"' . $item . '"';
|
||||
}, $arr);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace Nightmare\Database;
|
||||
|
||||
use ArrayObject;
|
||||
|
||||
class Row extends ArrayObject
|
||||
{
|
||||
/**
|
||||
* @param string $name
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get($name)
|
||||
{
|
||||
return $this[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param mixed $val
|
||||
* @return void
|
||||
*/
|
||||
public function __set($name, $val)
|
||||
{
|
||||
$this[$name] = $val;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Nightmare\Database;
|
||||
|
||||
use PDOStatement;
|
||||
use PDO;
|
||||
|
||||
class Statement extends PDOStatement
|
||||
{
|
||||
protected function __construct()
|
||||
{
|
||||
$this->setFetchMode(PDO::FETCH_CLASS, Row::class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
namespace Nightmare;
|
||||
|
||||
class Date
|
||||
{
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public static function now()
|
||||
{
|
||||
return time();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $day
|
||||
* @return int
|
||||
*/
|
||||
public static function start_day($day)
|
||||
{
|
||||
return mktime(00, 00, 00, (int) date('n'), $day);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $month
|
||||
* @return int
|
||||
*/
|
||||
public static function start_month($month)
|
||||
{
|
||||
return mktime(00, 00, 00, $month);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public static function start_year()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function current_day()
|
||||
{
|
||||
return date('d');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function current_month()
|
||||
{
|
||||
return date('m');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function current_year()
|
||||
{
|
||||
return date('Y');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $time
|
||||
* @return string
|
||||
*/
|
||||
public static function display_ago($time)
|
||||
{
|
||||
$times = time() - $time;
|
||||
|
||||
if ($times < 1) {
|
||||
$t = 'Vừa xong';
|
||||
} elseif ($times < 60) {
|
||||
$t = $times . ' giây trước';
|
||||
} elseif ($times < 3600) {
|
||||
$t = round($times / 60) . ' phút trước';
|
||||
} elseif ($times < 86400) {
|
||||
$t = round($times / 3600) . ' giờ trước';
|
||||
} elseif ($times < 2_592_000) {
|
||||
$t = round($times / 86400) . ' ngày trước';
|
||||
} elseif ($times < 31_536_000) {
|
||||
$t = round($times / 2_592_000) . ' tháng trước';
|
||||
} else {
|
||||
$t = round($times / 31_536_000) . ' năm trước';
|
||||
}
|
||||
|
||||
return $t;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace Nightmare\DesignPattern;
|
||||
|
||||
use Exception;
|
||||
|
||||
class Singleton
|
||||
{
|
||||
/**
|
||||
* @var self|null
|
||||
*/
|
||||
private static $instance = null;
|
||||
|
||||
/**
|
||||
* gets the instance via lazy initialization (created on first usage)
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public static function get_instance()
|
||||
{
|
||||
if (self::$instance === null) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* is not allowed to call from outside to prevent from creating multiple instances,
|
||||
* to use the singleton, you have to obtain the instance from Singleton::getInstance() instead
|
||||
*/
|
||||
private function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* prevent the instance from being cloned (which would create a second instance of it)
|
||||
*/
|
||||
private function __clone()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* prevent from being unserialized (which would create a second instance of it)
|
||||
*/
|
||||
public function __wakeup()
|
||||
{
|
||||
throw new Exception("Cannot unserialize singleton");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace Nightmare\Epub;
|
||||
|
||||
use Nightmare\Fs;
|
||||
use Exception;
|
||||
use ZipArchive;
|
||||
|
||||
class Reader {
|
||||
private $zip;
|
||||
private $file_path;
|
||||
|
||||
// private $epub_opf_file;
|
||||
private $epub_opf_dir;
|
||||
|
||||
public function __construct($file_path) {
|
||||
$this->file_path = $file_path;
|
||||
$this->zip = new ZipArchive();
|
||||
|
||||
$this->check();
|
||||
$this->read_metadata();
|
||||
}
|
||||
|
||||
private function check() {
|
||||
// check file
|
||||
if (!is_file($this->file_path)) {
|
||||
throw new Exception('epub not exists or not permission');
|
||||
}
|
||||
|
||||
if (filesize($this->file_path) < 1) {
|
||||
throw new Exception('epub not exists or not permission');
|
||||
}
|
||||
|
||||
// check epub valid
|
||||
if ($this->zip->open($this->file_path) !== TRUE) {
|
||||
throw new Exception('epub read error');
|
||||
}
|
||||
|
||||
if ($this->zip->getFromName('mimetype') !== 'application/epub+zip') {
|
||||
throw new Exception('epub format error');
|
||||
}
|
||||
}
|
||||
|
||||
private function read_metadata() {
|
||||
$meta = $this->zip->getFromName('META-INF/container.xml');
|
||||
$meta = simplexml_load_string($meta);
|
||||
$this->epub_opf_dir = (string) $meta->rootfiles->rootfile['full-path'];
|
||||
|
||||
$meta = $this->zip->getFromName($this->epub_opf_dir);
|
||||
$meta = simplexml_load_string($meta);
|
||||
|
||||
var_dump($meta->metadata->children('http://purl.org/dc/elements/1.1/'));
|
||||
}
|
||||
}
|
||||
+213
@@ -0,0 +1,213 @@
|
||||
<?php
|
||||
|
||||
namespace Nightmare;
|
||||
|
||||
use Exception;
|
||||
use FilesystemIterator;
|
||||
use RecursiveCallbackFilterIterator;
|
||||
use RecursiveDirectoryIterator;
|
||||
use RecursiveIteratorIterator;
|
||||
use SplFileInfo;
|
||||
|
||||
// file system
|
||||
class Fs
|
||||
{
|
||||
/*
|
||||
* file, file1, file2...
|
||||
*/
|
||||
/**
|
||||
* @param string $file_name_body
|
||||
* @param string $file_ext
|
||||
* @return string
|
||||
*/
|
||||
public function name_increment($file_name_body, $file_ext)
|
||||
{
|
||||
$i = 1;
|
||||
$file_exists = true;
|
||||
|
||||
do {
|
||||
$file_save = $file_name_body . $i . '.' . $file_ext;
|
||||
|
||||
if (!file_exists($file_save)) {
|
||||
$file_exists = false;
|
||||
}
|
||||
|
||||
$i++;
|
||||
} while ($file_exists);
|
||||
|
||||
return $file_save;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
public static function get_extension($name)
|
||||
{
|
||||
return (new SplFileInfo($name))->getExtension();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @return int
|
||||
*/
|
||||
public static function size($path)
|
||||
{
|
||||
if (!is_dir($path)) {
|
||||
return filesize($path);
|
||||
}
|
||||
|
||||
$size = 0;
|
||||
|
||||
$iterator = new RecursiveIteratorIterator(
|
||||
new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS | FilesystemIterator::FOLLOW_SYMLINKS),
|
||||
RecursiveIteratorIterator::LEAVES_ONLY
|
||||
);
|
||||
|
||||
foreach ($iterator as $file) {
|
||||
if ($file->isFile()) {
|
||||
$size += $file->getSize();
|
||||
}
|
||||
}
|
||||
|
||||
return $size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $fileSize
|
||||
* @return string
|
||||
*/
|
||||
public static function sizen($fileSize)
|
||||
{
|
||||
$size = floatval($fileSize);
|
||||
|
||||
if ($size < 1024) {
|
||||
$s = $size . ' B';
|
||||
} elseif ($size < 1048576) {
|
||||
$s = round($size / 1024, 2) . ' KB';
|
||||
} elseif ($size < 1073741824) {
|
||||
$s = round($size / 1048576, 2) . ' MB';
|
||||
} elseif ($size < 1099511627776) {
|
||||
$s = round($size / 1073741824, 2) . ' GB';
|
||||
} elseif ($size < 1125899906842624) {
|
||||
$s = round($size / 1099511627776, 2) . ' TB';
|
||||
} elseif ($size < 1152921504606846976) {
|
||||
$s = round($size / 1125899906842624, 2) . ' PB';
|
||||
} elseif ($size < 1.1805916207174E+21) {
|
||||
$s = round($size / 1152921504606846976, 2) . ' EB';
|
||||
} elseif ($size < 1.2089258196146E+24) {
|
||||
$s = round($size / 1.1805916207174E+21, 2) . ' ZB';
|
||||
} else {
|
||||
$s = round($size / 1.2089258196146E+24, 2) . ' YB';
|
||||
}
|
||||
|
||||
return $s;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @return bool
|
||||
*/
|
||||
public static function remove($path)
|
||||
{
|
||||
if (is_link($path)) {
|
||||
return unlink($path);
|
||||
}
|
||||
|
||||
if (is_file($path)) {
|
||||
return unlink($path);
|
||||
}
|
||||
|
||||
if (is_dir($path)) {
|
||||
$files = array_diff(scandir($path), ['.', '..']);
|
||||
foreach ($files as $file) {
|
||||
$filePath = $path . DIRECTORY_SEPARATOR . $file;
|
||||
if (!self::remove($filePath)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return rmdir($path);
|
||||
}
|
||||
|
||||
if (!file_exists($path)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
throw new Exception('remove error, not match file type');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @param array $excludes
|
||||
* @return RecursiveIteratorIterator
|
||||
*/
|
||||
public static function read_full_dir($path, $excludes = [])
|
||||
{
|
||||
$directory = new RecursiveDirectoryIterator(
|
||||
$path,
|
||||
FilesystemIterator::UNIX_PATHS
|
||||
| FilesystemIterator::SKIP_DOTS
|
||||
);
|
||||
|
||||
$filter = new RecursiveCallbackFilterIterator($directory, function ($current, $key, $iterator) use ($path, $excludes) {
|
||||
$relativePath = Str::replace_first($path, '', $current->getPathname());
|
||||
|
||||
foreach ($excludes as $exclude) {
|
||||
if (empty($exclude)) {
|
||||
continue;
|
||||
}
|
||||
//var_dump($relativePath);
|
||||
//var_dump($exclude);
|
||||
|
||||
$exclude = trim($exclude);
|
||||
$exclude = trim($exclude, '/');
|
||||
$relativePath = trim($relativePath, '/');
|
||||
|
||||
if (str_ends_with($relativePath, $exclude)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
return new RecursiveIteratorIterator(
|
||||
$filter,
|
||||
RecursiveIteratorIterator::SELF_FIRST
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string ...$paths
|
||||
* @return string
|
||||
*/
|
||||
public static function join_path(...$paths)
|
||||
{
|
||||
return preg_replace('#/+#', '/', implode('/', $paths));
|
||||
}
|
||||
|
||||
/**
|
||||
* Lấy tên chủ sở hữu file theo tên file
|
||||
* @param string $filename
|
||||
* @return string
|
||||
*/
|
||||
public static function get_owner_name($filename)
|
||||
{
|
||||
$owner_id = @fileowner($filename);
|
||||
if ($owner_id === false) {
|
||||
return '';
|
||||
}
|
||||
return self::get_owner_name_by_id($owner_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lấy tên chủ sở hữu theo user ID
|
||||
* @param int $id
|
||||
* @return string
|
||||
*/
|
||||
public static function get_owner_name_by_id($id)
|
||||
{
|
||||
$info = @posix_getpwuid($id);
|
||||
return $info['name'] ?? '';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Nightmare\Http;
|
||||
|
||||
use Symfony\Component\BrowserKit\HttpBrowser;
|
||||
use Symfony\Component\BrowserKit\History;
|
||||
use Symfony\Component\BrowserKit\CookieJar;
|
||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||
|
||||
class Browser extends HttpBrowser
|
||||
{
|
||||
/**
|
||||
* @param HttpClientInterface|null $client
|
||||
* @param History|null $history
|
||||
* @param CookieJar|null $cookieJar
|
||||
*/
|
||||
public function __construct($client = null, $history = null, $cookieJar = null)
|
||||
{
|
||||
parent::__construct($client ?? new Client(), $history, $cookieJar); // @phpstan-ignore-line
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $userAgent
|
||||
* @return void
|
||||
*/
|
||||
public function setUserAgent($userAgent) {
|
||||
$this->setServerParameter('HTTP_USER_AGENT', $userAgent);
|
||||
}
|
||||
}
|
||||
Executable
+7
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace Nightmare\Http;
|
||||
|
||||
use Symfony\Component\HttpClient\CurlHttpClient;
|
||||
|
||||
class_alias(CurlHttpClient::class, 'Nightmare\Http\Client');
|
||||
Executable
+7
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace Nightmare\Http;
|
||||
|
||||
use Symfony\Component\HttpClient\HttpClient;
|
||||
|
||||
class_alias(HttpClient::class, 'Nightmare\Http\ClientNative');
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace Nightmare\Http;
|
||||
|
||||
class Curl extends \Curl\Curl {
|
||||
/**
|
||||
* @param string|null $base_url
|
||||
* @param array $options
|
||||
*/
|
||||
public function __construct($base_url = null, $options = [])
|
||||
{
|
||||
parent::__construct($base_url, $options);
|
||||
$this->setDefaultJsonDecoder($assoc = true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace Nightmare\Http;
|
||||
|
||||
class Http
|
||||
{
|
||||
/**
|
||||
* @param mixed $data
|
||||
* @param int $status
|
||||
* @param array $headers
|
||||
* @return Response
|
||||
*/
|
||||
public static function response($data = null, $status = 200, $headers = [])
|
||||
{
|
||||
return new Response($data, $status, $headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
* @param int $status
|
||||
* @return void
|
||||
*/
|
||||
public static function redirect($url, $status = 301)
|
||||
{
|
||||
@ob_end_clean();
|
||||
http_response_code($status);
|
||||
header('Location: ' . $url);
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public static function refresh()
|
||||
{
|
||||
@ob_end_clean();
|
||||
header('Refresh: 0');
|
||||
exit;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,482 @@
|
||||
<?php
|
||||
|
||||
namespace Nightmare\Http;
|
||||
|
||||
use Nightmare\Json;
|
||||
use RuntimeException;
|
||||
|
||||
class Request
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public static $file;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public static $header;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public static $server;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public static $payload;
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public static function init()
|
||||
{
|
||||
/*
|
||||
{
|
||||
$request_uri = @parse_url($_SERVER['REQUEST_URI'] ?? '');
|
||||
$add_get = [];
|
||||
|
||||
if (isset($request_uri['query'])) {
|
||||
parse_str($request_uri['query'], $add_get);
|
||||
}
|
||||
|
||||
$_GET = array_merge($_GET, $add_get);
|
||||
$_REQUEST = array_merge($_REQUEST, $add_get);
|
||||
}
|
||||
*/
|
||||
//self::init_payload();
|
||||
//self::init_file();
|
||||
}
|
||||
|
||||
// common
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_cli()
|
||||
{
|
||||
return \php_sapi_name() === 'cli';
|
||||
}
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_cli_server()
|
||||
{
|
||||
return \php_sapi_name() === 'cli-server';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function script_name()
|
||||
{
|
||||
return self::server('script_name');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function method()
|
||||
{
|
||||
return strtolower((string) self::server('REQUEST_METHOD', 'get'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_method($value)
|
||||
{
|
||||
return strtolower($value) === self::method();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_ajax() {
|
||||
return self::has_header('X_REQUESTED_WITH') &&
|
||||
strtolower((string) self::header('X_REQUESTED_WITH')) === 'xmlhttprequest';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function ip()
|
||||
{
|
||||
$keys = [
|
||||
'HTTP_CLIENT_IP',
|
||||
'HTTP_X_FORWARDED_FOR',
|
||||
'HTTP_X_FORWARDED',
|
||||
'HTTP_FORWARDED_FOR',
|
||||
'HTTP_FORWARDED',
|
||||
'REMOTE_ADDR'
|
||||
];
|
||||
foreach ($keys as $key) {
|
||||
if (isset($_SERVER[$key])) {
|
||||
return $_SERVER[$key];
|
||||
}
|
||||
}
|
||||
|
||||
return '127.0.0.1';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function user_agent()
|
||||
{
|
||||
return (string) self::header('user_agent');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function referer()
|
||||
{
|
||||
return (string) self::header('referer');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function host()
|
||||
{
|
||||
return (string) self::header('host');
|
||||
}
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function base_url()
|
||||
{
|
||||
return self::server('request_scheme', 'http')
|
||||
. '://'
|
||||
. self::server('server_name', 'localhost');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $mode
|
||||
* @return string
|
||||
*/
|
||||
public static function uri($mode = 'full')
|
||||
{
|
||||
$uri = self::server('request_uri');
|
||||
|
||||
switch ($mode) {
|
||||
case 'request':
|
||||
return $uri;
|
||||
case 'no_query':
|
||||
return strtok($uri, '?');
|
||||
default:
|
||||
return self::base_url() . $uri;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function query_string()
|
||||
{
|
||||
return (string) self::server('query_string');
|
||||
}
|
||||
|
||||
// HEADER
|
||||
/**
|
||||
* @param string $key
|
||||
* @param mixed $default
|
||||
* @return mixed
|
||||
*/
|
||||
public static function header($key = '', $default = null)
|
||||
{
|
||||
if ($key === '') {
|
||||
$headers = [];
|
||||
foreach ($_SERVER as $key => $value) {
|
||||
if (str_starts_with($key, 'HTTP_')) {
|
||||
$headers[str_replace('_', '-', strtolower(substr($key, 5)))] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $headers;
|
||||
}
|
||||
|
||||
return $_SERVER['HTTP_' . str_replace('-', '_', strtoupper($key))] ?? $default;
|
||||
}
|
||||
/**
|
||||
* @param string $key
|
||||
* @return bool
|
||||
*/
|
||||
public static function has_header($key)
|
||||
{
|
||||
return isset($_SERVER['HTTP_' . strtoupper($key)]);
|
||||
}
|
||||
|
||||
// GET
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param mixed $default
|
||||
* @return mixed
|
||||
*/
|
||||
public static function get($key = '', $default = null)
|
||||
{
|
||||
if ($key === '') {
|
||||
return $_GET;
|
||||
}
|
||||
|
||||
return $_GET[$key] ?? $default;
|
||||
}
|
||||
/**
|
||||
* @param string $key
|
||||
* @return bool
|
||||
*/
|
||||
public static function has_get($key)
|
||||
{
|
||||
return isset($_GET[$key]);
|
||||
}
|
||||
/**
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @return void
|
||||
*/
|
||||
public static function set_get($key, $value)
|
||||
{
|
||||
$_GET[$key] = $value;
|
||||
}
|
||||
|
||||
// POST
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param mixed $default
|
||||
* @return mixed
|
||||
*/
|
||||
public static function post($key, $default = null)
|
||||
{
|
||||
if ($key === '') {
|
||||
return $_POST;
|
||||
}
|
||||
|
||||
return $_POST[$key] ?? $default;
|
||||
}
|
||||
/**
|
||||
* @param string $key
|
||||
* @return bool
|
||||
*/
|
||||
public static function has_post($key)
|
||||
{
|
||||
return isset($_POST[$key]);
|
||||
}
|
||||
/**
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @return void
|
||||
*/
|
||||
public static function set_post($key, $value)
|
||||
{
|
||||
$_POST[$key] = $value;
|
||||
}
|
||||
|
||||
// COOKIE
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param mixed $default
|
||||
* @return mixed
|
||||
*/
|
||||
public static function cookie($key, $default = null)
|
||||
{
|
||||
if ($key === '') {
|
||||
return $_COOKIE;
|
||||
}
|
||||
|
||||
return $_COOKIE[$key] ?? $default;
|
||||
}
|
||||
/**
|
||||
* @param string $key
|
||||
* @return bool
|
||||
*/
|
||||
public static function has_cookie($key)
|
||||
{
|
||||
return isset($_COOKIE[$key]);
|
||||
}
|
||||
/**
|
||||
* @param string $key
|
||||
* @param string $value
|
||||
* @return void
|
||||
*/
|
||||
public static function set_cookie($key, $value)
|
||||
{
|
||||
$_COOKIE[$key] = $value;
|
||||
}
|
||||
|
||||
// SESSION
|
||||
|
||||
/**
|
||||
* @param string $prefix
|
||||
* @param int $ttl
|
||||
* @return void
|
||||
*/
|
||||
public static function session_start($prefix = 'sess_', $ttl = 86400)
|
||||
{
|
||||
//session_set_save_handler(new \Nightmare\Session\Storage\Apcu($prefix, $ttl));
|
||||
|
||||
if (PHP_SESSION_ACTIVE === session_status()) {
|
||||
throw new RuntimeException('Failed to start the session: already started by PHP.');
|
||||
}
|
||||
|
||||
if (!\session_start()) {
|
||||
throw new RuntimeException('Failed to start the session.');
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param string $key
|
||||
* @param mixed $default
|
||||
* @return mixed
|
||||
*/
|
||||
public static function session($key, $default = null)
|
||||
{
|
||||
if ($key === '') {
|
||||
return $_SESSION;
|
||||
}
|
||||
|
||||
return $_SESSION[$key] ?? $default;
|
||||
}
|
||||
/**
|
||||
* @param string $key
|
||||
* @return bool
|
||||
*/
|
||||
public static function has_session($key)
|
||||
{
|
||||
return isset($_SESSION[$key]);
|
||||
}
|
||||
/**
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @return void
|
||||
*/
|
||||
public static function set_session($key, $value)
|
||||
{
|
||||
$_SESSION[$key] = $value;
|
||||
}
|
||||
/**
|
||||
* @param string $key
|
||||
* @return void
|
||||
*/
|
||||
public static function unset_session($key)
|
||||
{
|
||||
unset($_SESSION[$key]);
|
||||
}
|
||||
|
||||
|
||||
// SERVER
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param mixed $default
|
||||
* @return mixed
|
||||
*/
|
||||
public static function server($key, $default = null)
|
||||
{
|
||||
if ($key === '') {
|
||||
return $_SERVER;
|
||||
}
|
||||
|
||||
return (string) (isset($_SERVER[$key]) ? $_SERVER[$key] : (isset($_SERVER[strtoupper($key)]) ? $_SERVER[strtoupper($key)] : $default));
|
||||
}
|
||||
/**
|
||||
* @param string $key
|
||||
* @return bool
|
||||
*/
|
||||
public static function has_server($key)
|
||||
{
|
||||
return isset($_SERVER[$key]) ? true : isset($_SERVER[strtoupper($key)]);
|
||||
}
|
||||
|
||||
// FILES
|
||||
/**
|
||||
* @param string $key
|
||||
* @return array|null
|
||||
*/
|
||||
public static function file($key)
|
||||
{
|
||||
if ($key === '') {
|
||||
return $_FILES;
|
||||
}
|
||||
|
||||
if (!isset($_FILES[$key])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!is_array($_FILES[$key]['name'])) {
|
||||
return [$_FILES[$key]];
|
||||
}
|
||||
|
||||
$tmp = [];
|
||||
foreach ($_FILES[$key] as $k => $v) {
|
||||
$fCount = count($_FILES[$key]['name']);
|
||||
$fKeys = array_keys($_FILES[$key]);
|
||||
|
||||
for ($i = 0; $i < $fCount; $i++) {
|
||||
foreach ($fKeys as $fKey) {
|
||||
$tmp[$key][$i][$fKey] = $_FILES[$key][$fKey][$i];
|
||||
}
|
||||
}
|
||||
}
|
||||
return $tmp;
|
||||
}
|
||||
|
||||
// REQUEST
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param mixed $default
|
||||
* @return mixed
|
||||
*/
|
||||
public static function request($key, $default = null)
|
||||
{
|
||||
if ($key === '') {
|
||||
return $_REQUEST;
|
||||
}
|
||||
|
||||
return $_REQUEST[$key] ?? $default;
|
||||
}
|
||||
/**
|
||||
* @param string $key
|
||||
* @return bool
|
||||
*/
|
||||
public static function has_request($key)
|
||||
{
|
||||
return isset($_REQUEST[$key]);
|
||||
}
|
||||
|
||||
// PAYLOAD
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public static function init_payload()
|
||||
{
|
||||
self::$payload = Json::decode(file_get_contents('php://input') ?: '[]', true);
|
||||
}
|
||||
/**
|
||||
* @param string $key
|
||||
* @return bool
|
||||
*/
|
||||
public static function has_payload($key)
|
||||
{
|
||||
return isset(self::$payload[$key]);
|
||||
}
|
||||
/**
|
||||
* @param string $key
|
||||
* @param mixed $default
|
||||
* @return mixed
|
||||
*/
|
||||
public static function payload($key = '', $default = null)
|
||||
{
|
||||
if ($key === '') {
|
||||
return self::$payload;
|
||||
}
|
||||
|
||||
return self::$payload[$key] ?? $default;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
<?php
|
||||
|
||||
namespace Nightmare\Http;
|
||||
|
||||
class Response
|
||||
{
|
||||
private $data;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $status;
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $headers = [];
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private static $is_sended = false;
|
||||
|
||||
/**
|
||||
* @param mixed $data
|
||||
* @param int $status
|
||||
* @param array $headers
|
||||
*/
|
||||
public function __construct(
|
||||
$data = null,
|
||||
$status = 200,
|
||||
$headers = []
|
||||
) {
|
||||
$this->data = $data;
|
||||
$this->status = $status;
|
||||
$this->headers = $headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $data
|
||||
* @return self
|
||||
*/
|
||||
public function data($data)
|
||||
{
|
||||
$this->data = $data;
|
||||
return $this;
|
||||
}
|
||||
/**
|
||||
* @param int $status
|
||||
* @return self
|
||||
*/
|
||||
public function status($status)
|
||||
{
|
||||
$this->status = $status;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $prettify
|
||||
* @return self
|
||||
*/
|
||||
public function json($prettify = false)
|
||||
{
|
||||
$this->headers += ['Content-Type: application/json'];
|
||||
|
||||
if (is_array($this->data) || is_object($this->data)) {
|
||||
$flags = 0;
|
||||
|
||||
$flags |= JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES;
|
||||
|
||||
if ($prettify) {
|
||||
$flags |= JSON_PRETTY_PRINT;
|
||||
}
|
||||
|
||||
$this->data = json_encode($this->data, $flags);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $headers
|
||||
* @return self
|
||||
*/
|
||||
public function headers($headers)
|
||||
{
|
||||
$this->headers = $headers;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function send()
|
||||
{
|
||||
static $is_sended;
|
||||
|
||||
if ($is_sended) {
|
||||
return;
|
||||
} else {
|
||||
$is_sended = true;
|
||||
}
|
||||
|
||||
if (is_array($this->data)) {
|
||||
$this->json();
|
||||
}
|
||||
|
||||
http_response_code($this->status);
|
||||
|
||||
$this->headers = array_unique($this->headers);
|
||||
foreach ($this->headers as $header) {
|
||||
header($header);
|
||||
}
|
||||
|
||||
echo $this->data;
|
||||
|
||||
if (\function_exists('fastcgi_finish_request')) {
|
||||
fastcgi_finish_request();
|
||||
} elseif (\function_exists('litespeed_finish_request')) {
|
||||
litespeed_finish_request();
|
||||
} elseif (!\in_array(\PHP_SAPI, ['cli', 'phpdbg', 'embed'], true)) {
|
||||
static::close_output_buffers(0, true);
|
||||
flush();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $targetLevel
|
||||
* @param bool $flush
|
||||
* @return void
|
||||
*/
|
||||
public static function close_output_buffers($targetLevel, $flush)
|
||||
{
|
||||
$status = ob_get_status(true);
|
||||
$level = \count($status);
|
||||
$flags = \PHP_OUTPUT_HANDLER_REMOVABLE | ($flush ? \PHP_OUTPUT_HANDLER_FLUSHABLE : \PHP_OUTPUT_HANDLER_CLEANABLE);
|
||||
|
||||
while ($level-- > $targetLevel && ($s = $status[$level]) && (!isset($s['del']) ? !isset($s['flags']) || ($s['flags'] & $flags) === $flags : $s['del'])) {
|
||||
if ($flush) {
|
||||
ob_end_flush();
|
||||
} else {
|
||||
ob_end_clean();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function finish() {
|
||||
if (\function_exists('fastcgi_finish_request')) {
|
||||
fastcgi_finish_request();
|
||||
} elseif (\function_exists('litespeed_finish_request')) {
|
||||
litespeed_finish_request();
|
||||
} elseif (!\in_array(\PHP_SAPI, ['cli', 'phpdbg', 'embed'], true)) {
|
||||
static::close_output_buffers(0, true);
|
||||
flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
// json5
|
||||
|
||||
namespace Nightmare;
|
||||
|
||||
class Json
|
||||
{
|
||||
/**
|
||||
* @param mixed ...$args
|
||||
* @return string|false
|
||||
*/
|
||||
public static function encode(...$args) {
|
||||
return json_encode(...$args);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $data
|
||||
* @param mixed ...$args
|
||||
* @return mixed
|
||||
*/
|
||||
public static function decode($data, ...$args) {
|
||||
$assoc = true;
|
||||
if (count($args) > 0) {
|
||||
$assoc = $args[0];
|
||||
}
|
||||
|
||||
try {
|
||||
return json5_decode($data, $assoc, ...array_slice($args, 1));
|
||||
} catch(\Throwable $e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $file
|
||||
* @param mixed ...$args
|
||||
* @return int|false
|
||||
*/
|
||||
public static function encode_file($file, ...$args) {
|
||||
return file_put_contents($file, json_encode(...$args));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $file
|
||||
* @param mixed ...$args
|
||||
* @return mixed
|
||||
*/
|
||||
public static function decode_file($file, ...$args) {
|
||||
$assoc = true;
|
||||
if (count($args) > 0) {
|
||||
$assoc = $args[0];
|
||||
}
|
||||
return self::decode(file_get_contents($file), $assoc, ...array_slice($args, 1));
|
||||
}
|
||||
}
|
||||
Executable
+57
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace Nightmare\Session\Storage;
|
||||
|
||||
use SessionHandlerInterface;
|
||||
use ReturnTypeWillChange;
|
||||
|
||||
class Apcu implements SessionHandlerInterface
|
||||
{
|
||||
private string $prefix;
|
||||
private int $ttl;
|
||||
|
||||
public function __construct(string $prefix = 'sess_', int $ttl = 86400)
|
||||
{
|
||||
$this->prefix = $prefix;
|
||||
$this->ttl = $ttl;
|
||||
}
|
||||
|
||||
#[ReturnTypeWillChange]
|
||||
public function close()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
#[ReturnTypeWillChange]
|
||||
public function destroy($id)
|
||||
{
|
||||
$key = $this->prefix . $id;
|
||||
return apcu_delete($key);
|
||||
}
|
||||
|
||||
#[ReturnTypeWillChange]
|
||||
public function gc($max_lifetime)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
#[ReturnTypeWillChange]
|
||||
public function open($path, $name)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
#[ReturnTypeWillChange]
|
||||
public function read($id)
|
||||
{
|
||||
$key = $this->prefix . $id;
|
||||
return apcu_exists($key) ? apcu_fetch($key) : '';
|
||||
}
|
||||
|
||||
#[ReturnTypeWillChange]
|
||||
public function write($id, $data)
|
||||
{
|
||||
$key = $this->prefix . $id;
|
||||
return apcu_store($key, $data, $this->ttl);
|
||||
}
|
||||
}
|
||||
+128
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
|
||||
namespace Nightmare;
|
||||
|
||||
class Str
|
||||
{
|
||||
/**
|
||||
* @param string $string
|
||||
* @return bool
|
||||
*/
|
||||
public static function empty($string)
|
||||
{
|
||||
return strlen($string) === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $string
|
||||
* @param int $words
|
||||
* @param string $end
|
||||
* @return string
|
||||
*/
|
||||
public static function word_cut($string, $words = 35, $end = '...')
|
||||
{
|
||||
preg_match('/^\s*+(?:\S++\s*+){1,' . $words . '}/u', $string, $matches);
|
||||
|
||||
if (!isset($matches[0]) || self::length($string) === self::length($matches[0])) {
|
||||
return $string;
|
||||
}
|
||||
|
||||
return rtrim($matches[0]) . $end;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $str
|
||||
* @return string
|
||||
*/
|
||||
public static function br2nl($str)
|
||||
{
|
||||
return preg_replace('#<br\s*/?>#i', PHP_EOL, $str);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $str
|
||||
* @return int
|
||||
*/
|
||||
public static function length($str)
|
||||
{
|
||||
return mb_strlen($str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Chuyển đổi tiếng Việt sang tiếng Anh
|
||||
* @param string $str
|
||||
* @return string
|
||||
*/
|
||||
public static function vn2en($str)
|
||||
{
|
||||
$unicode = [
|
||||
'a' => '/á|à|ả|ã|ạ|ă|ắ|ặ|ằ|ẳ|ẵ|â|ấ|ầ|ẩ|ẫ|ậ/',
|
||||
'd' => '/đ/',
|
||||
'e' => '/é|è|ẻ|ẽ|ẹ|ê|ế|ề|ể|ễ|ệ/',
|
||||
'i' => '/í|ì|ỉ|ĩ|ị/',
|
||||
'o' => '/ó|ò|ỏ|õ|ọ|ô|ố|ồ|ổ|ỗ|ộ|ơ|ớ|ờ|ở|ỡ|ợ/',
|
||||
'u' => '/ú|ù|ủ|ũ|ụ|ư|ứ|ừ|ử|ữ|ự/',
|
||||
'y' => '/ý|ỳ|ỷ|ỹ|ỵ/',
|
||||
|
||||
'A' => '/Á|À|Ả|Ã|Ạ|Ă|Ắ|Ặ|Ằ|Ằ|Ẵ|Â|Ấ|Ầ|Ẩ|Ẫ|Ậ/',
|
||||
'D' => '/Đ/',
|
||||
'E' => '/É|È|Ẻ|Ẽ|Ẹ|Ê|Ế|Ề|Ể|Ễ|Ệ/',
|
||||
'I' => '/Í|Ì|Ỉ|Ĩ|Ị/',
|
||||
'O' => '/Ó|Ò|Ỏ|Õ|Ọ|Ô|Ố|Ồ|Ổ|Ỗ|Ộ|Ơ|Ớ|Ờ|Ở|Ỡ|Ợ/',
|
||||
'U' => '/Ú|Ù|Ủ|Ũ|Ụ|Ư|Ứ|Ừ|Ử|Ữ|Ự/',
|
||||
'Y' => '/Ý|Ỳ|Ỷ|Ỹ|Ỵ/'
|
||||
];
|
||||
|
||||
return preg_replace(array_values($unicode), array_keys($unicode), $str);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $needle
|
||||
* @param string $replace
|
||||
* @param string $haystack
|
||||
* @return string
|
||||
*/
|
||||
public static function replace_first($needle, $replace, $haystack)
|
||||
{
|
||||
$pos = strpos($haystack, $needle);
|
||||
|
||||
if ($pos !== false) {
|
||||
return substr_replace($haystack, $replace, $pos, strlen($needle));
|
||||
}
|
||||
|
||||
return $haystack;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $text
|
||||
* @return string
|
||||
*/
|
||||
public static function to_unix_newline($text)
|
||||
{
|
||||
return str_replace([
|
||||
"\r\n", // windows
|
||||
"\r" // mac old
|
||||
], "\n", $text);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $str
|
||||
* @return string
|
||||
*/
|
||||
public function to_url($str) {
|
||||
$str = trim($str);
|
||||
$str = strtolower($str);
|
||||
$str = self::vn2en($str);
|
||||
|
||||
$str = html_entity_decode($str, ENT_QUOTES, 'UTF-8');
|
||||
|
||||
$str = str_replace('&', '-and-', $str);
|
||||
$str = str_replace(' ', '-', $str);
|
||||
|
||||
$str = preg_replace('#[^a-z0-9\-]#', '', $str);
|
||||
$str = preg_replace('#[-]{2,}#', '-', $str);
|
||||
$str = trim($str, '-');
|
||||
|
||||
return $str;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
namespace Nightmare;
|
||||
|
||||
class Trie
|
||||
{
|
||||
/** @var array */
|
||||
public $tree;
|
||||
|
||||
public function __construct() {
|
||||
$this->tree = [
|
||||
'value' => '',
|
||||
'child' => []
|
||||
];
|
||||
}
|
||||
|
||||
public function add($str, $data = '') {
|
||||
$length = mb_strlen($str);
|
||||
|
||||
if (!$length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$tree = &$this->tree;
|
||||
$chars = mb_str_split($str);
|
||||
$i = 0;
|
||||
|
||||
foreach ($chars as $char) {
|
||||
$i++;
|
||||
$is_end = $i === $length;
|
||||
$char = mb_ord($char);
|
||||
|
||||
if (!isset($tree['child'][$char])) {
|
||||
$tree['child'][$char] = [
|
||||
'value' => '',
|
||||
'child' => []
|
||||
];
|
||||
}
|
||||
|
||||
if ($is_end) {
|
||||
$tree['child'][$char]['value'] = (string) $data;
|
||||
}
|
||||
|
||||
$tree = &$tree['child'][$char];
|
||||
}
|
||||
}
|
||||
|
||||
// false, array
|
||||
public function search($str) {
|
||||
$length = mb_strlen($str);
|
||||
|
||||
if (!$length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$tree = &$this->tree;
|
||||
$chars = mb_str_split($str);
|
||||
$i = 0;
|
||||
|
||||
foreach ($chars as $char) {
|
||||
$i++;
|
||||
$is_end = $i === $length;
|
||||
$char = mb_ord($char);
|
||||
|
||||
if (!isset($tree['child'][$char])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($is_end) {
|
||||
return [
|
||||
'value' => $tree['child'][$char]['value'] ?? '',
|
||||
'is_end' => count($tree['child'][$char]['child']) === 0
|
||||
];
|
||||
}
|
||||
|
||||
$tree = &$tree['child'][$char];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace Nightmare;
|
||||
|
||||
class Uuid
|
||||
{
|
||||
public static function v4()
|
||||
{
|
||||
$b = random_bytes(16);
|
||||
$b[6] = chr(ord($b[6]) & 0x0f | 0x40);
|
||||
$b[8] = chr(ord($b[8]) & 0x3f | 0x80);
|
||||
|
||||
$hex = bin2hex($b);
|
||||
|
||||
return sprintf(
|
||||
'%s%s-%s-%s-%s-%s%s%s',
|
||||
substr($hex, 0, 4),
|
||||
substr($hex, 4, 4),
|
||||
substr($hex, 8, 4),
|
||||
substr($hex, 12, 4),
|
||||
substr($hex, 16, 4),
|
||||
substr($hex, 20, 4),
|
||||
substr($hex, 24, 4),
|
||||
substr($hex, 28, 4)
|
||||
);
|
||||
}
|
||||
|
||||
// uuidv7 see https://www.rfc-editor.org/rfc/rfc9562#name-uuid-version-7
|
||||
public static function v7()
|
||||
{
|
||||
// 1) Lấy timestamp mili-giây từ Unix Epoch (UTC)
|
||||
$unix_ms = (int) (microtime(true) * 1000);
|
||||
|
||||
// 2) 48-bit timestamp big-endian -> 6 byte
|
||||
// N = 32-bit big-endian, n = 16-bit big-endian
|
||||
$time_bytes = pack('Nn', $unix_ms >> 16, $unix_ms & 0xFFFF);
|
||||
|
||||
// 3) 10 byte ngẫu nhiên (crypto-safe)
|
||||
$rand_bytes = random_bytes(10);
|
||||
|
||||
// 4) Ghép thành 16 byte
|
||||
$bytes = $time_bytes . $rand_bytes;
|
||||
|
||||
// 5) Set version 7 (0111) vào high nibble của byte thứ 7 (index 6)
|
||||
$bytes[6] = chr((ord($bytes[6]) & 0x0F) | 0x70);
|
||||
|
||||
// 6) Set variant RFC 4122 -> 10xxxxxx vào byte thứ 9 (index 8)
|
||||
$bytes[8] = chr((ord($bytes[8]) & 0x3F) | 0x80);
|
||||
|
||||
// 7) Chuyển sang dạng string 8-4-4-4-12
|
||||
$hex = bin2hex($bytes);
|
||||
|
||||
return sprintf(
|
||||
'%s-%s-%s-%s-%s',
|
||||
substr($hex, 0, 8),
|
||||
substr($hex, 8, 4),
|
||||
substr($hex, 12, 4),
|
||||
substr($hex, 16, 4),
|
||||
substr($hex, 20),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace Nightmare;
|
||||
|
||||
use Symfony\Component\Yaml\Yaml as Yaml2;
|
||||
|
||||
class Yaml
|
||||
{
|
||||
/**
|
||||
* @param string $data
|
||||
* @return mixed
|
||||
*/
|
||||
public static function parse($data) {
|
||||
return Yaml2::parse($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $data
|
||||
* @param int $inline
|
||||
* @param int $indent
|
||||
* @param int $flags
|
||||
* @return string
|
||||
*/
|
||||
public static function dump($data, $inline = 2, $indent = 4, $flags = 0) {
|
||||
return Yaml2::dump($data, $inline, $indent, $flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $filename
|
||||
* @param mixed $data
|
||||
* @param int $inline
|
||||
* @param int $indent
|
||||
* @param int $flags
|
||||
* @return void
|
||||
*/
|
||||
public static function dump_file($filename, $data, $inline = 2, $indent = 4, $flags = 0) {
|
||||
file_put_contents($filename, Yaml2::dump($data, $inline, $indent, $flags));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $filename
|
||||
* @return mixed
|
||||
*/
|
||||
public static function parse_file($filename) {
|
||||
return Yaml2::parseFile($filename);
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace Nightmare;
|
||||
|
||||
use ZipArchive;
|
||||
use SplFileInfo;
|
||||
|
||||
class Zip extends ZipArchive {
|
||||
/**
|
||||
* @param string $path
|
||||
* @param string|null $relative
|
||||
* @return bool
|
||||
*/
|
||||
public function add($path, $relative = null)
|
||||
{
|
||||
if (!file_exists($path)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$file = new SplFileInfo($path);
|
||||
$path = $file->getPathname();
|
||||
$pathRelative = $path;
|
||||
|
||||
if ($relative) {
|
||||
$pathRelative = substr($path, strlen($relative));
|
||||
}
|
||||
|
||||
if ($file->isFile()) {
|
||||
$this->addFile($path, $pathRelative);
|
||||
}
|
||||
|
||||
if ($file->isDir()) {
|
||||
$this->addEmptyDir($pathRelative);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Vendored
+207
@@ -0,0 +1,207 @@
|
||||
<?php
|
||||
|
||||
namespace nightmare;
|
||||
|
||||
class cache
|
||||
{
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private static $debug = false;
|
||||
|
||||
/**
|
||||
* @var int|null
|
||||
*/
|
||||
private static $expire = null;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private static $prefix = '';
|
||||
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
private static $adapter;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private static $adapters = [];
|
||||
|
||||
// common
|
||||
|
||||
/**
|
||||
* @param bool $debug
|
||||
* @return void
|
||||
*/
|
||||
public static function set_debug($debug)
|
||||
{
|
||||
self::$debug = $debug;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $prefix
|
||||
* @return void
|
||||
*/
|
||||
public static function set_prefix($prefix)
|
||||
{
|
||||
self::$prefix = $prefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int|null $ttl
|
||||
* @return void
|
||||
*/
|
||||
public static function set_expire($ttl = null)
|
||||
{
|
||||
self::$expire = $ttl;
|
||||
}
|
||||
|
||||
// adapter
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @return void
|
||||
*/
|
||||
public static function set_adapter($key)
|
||||
{
|
||||
self::$adapter = self::$adapters[$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @return mixed
|
||||
*/
|
||||
public static function get_adapter($key)
|
||||
{
|
||||
return self::$adapters[$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param mixed $adapter
|
||||
* @return void
|
||||
*/
|
||||
public static function add_adapter($key, $adapter)
|
||||
{
|
||||
self::$adapters = array_merge(self::$adapters, [$key => $adapter]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @return void
|
||||
*/
|
||||
public function remove_adapter($key)
|
||||
{
|
||||
unset(self::$adapters[$key]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function get_adapters()
|
||||
{
|
||||
return self::$adapters;
|
||||
}
|
||||
|
||||
// cache
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @return bool
|
||||
*/
|
||||
public static function has($key)
|
||||
{
|
||||
return self::$adapter->hasItem(self::$prefix . $key);
|
||||
}
|
||||
|
||||
// truyen 1 tham so - lay binh thuong
|
||||
// truyen 2 tham so tro len - luu cache cho lan sau
|
||||
/**
|
||||
* @param string $key
|
||||
* @param mixed $default
|
||||
* @param array $opt
|
||||
* @return mixed
|
||||
*/
|
||||
public static function get($key, $default = null, $opt = [])
|
||||
{
|
||||
$opt += [
|
||||
'expire' => self::$expire,
|
||||
'debug' => false,
|
||||
'save' => true,
|
||||
'save_if' => null, // ?callable
|
||||
];
|
||||
|
||||
if (self::$debug || $opt['debug']) {
|
||||
self::unset(self::$prefix . $key);
|
||||
}
|
||||
|
||||
// get cache
|
||||
$item = self::$adapter->getItem(self::$prefix . $key);
|
||||
|
||||
if ($item->isHit()) {
|
||||
return $item->get();
|
||||
} else {
|
||||
if (is_callable($default)) {
|
||||
$default = call_user_func($default, $opt);
|
||||
}
|
||||
|
||||
if ($opt['save']) {
|
||||
$save = false;
|
||||
|
||||
if (is_callable($opt['save_if'])) {
|
||||
if (call_user_func($opt['save_if'], $default)) {
|
||||
$save = true;
|
||||
}
|
||||
} else {
|
||||
$save = true;
|
||||
}
|
||||
|
||||
if ($save) {
|
||||
self::set($key, $default, $opt['expire']);
|
||||
}
|
||||
}
|
||||
|
||||
return $default;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @param int|null $expire
|
||||
* @return bool
|
||||
*/
|
||||
public static function set($key, $value, $expire = null)
|
||||
{
|
||||
$item = self::$adapter->getItem(self::$prefix . $key);
|
||||
|
||||
if ($expire !== null) {
|
||||
$item->expiresAfter($expire);
|
||||
} elseif (self::$expire !== null) {
|
||||
$item->expiresAfter(self::$expire);
|
||||
}
|
||||
|
||||
$item->set($value);
|
||||
return self::$adapter->save($item);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @return bool
|
||||
*/
|
||||
public static function unset($key)
|
||||
{
|
||||
return self::$adapter->deleteItem(self::$prefix . $key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $prefix
|
||||
* @return bool
|
||||
*/
|
||||
public static function clear($prefix = '')
|
||||
{
|
||||
return self::$adapter->clear($prefix);
|
||||
}
|
||||
}
|
||||
Vendored
+207
@@ -0,0 +1,207 @@
|
||||
<?php
|
||||
|
||||
namespace nightmare;
|
||||
|
||||
class cache
|
||||
{
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $debug = false;
|
||||
|
||||
/**
|
||||
* @var int|null
|
||||
*/
|
||||
private $expire = null;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $prefix = '';
|
||||
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
private $adapter;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $adapters = [];
|
||||
|
||||
// common
|
||||
|
||||
/**
|
||||
* @param bool $debug
|
||||
* @return void
|
||||
*/
|
||||
public function set_debug($debug)
|
||||
{
|
||||
self::$debug = $debug;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $prefix
|
||||
* @return void
|
||||
*/
|
||||
public function set_prefix($prefix)
|
||||
{
|
||||
self::$prefix = $prefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int|null $ttl
|
||||
* @return void
|
||||
*/
|
||||
public function set_expire($ttl = null)
|
||||
{
|
||||
self::$expire = $ttl;
|
||||
}
|
||||
|
||||
// adapter
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @return void
|
||||
*/
|
||||
public function set_adapter($key)
|
||||
{
|
||||
self::$adapter = self::$adapters[$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function get_adapter($key)
|
||||
{
|
||||
return self::$adapters[$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param mixed $adapter
|
||||
* @return void
|
||||
*/
|
||||
public function add_adapter($key, $adapter)
|
||||
{
|
||||
self::$adapters = array_merge(self::$adapters, [$key => $adapter]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @return void
|
||||
*/
|
||||
public function remove_adapter($key)
|
||||
{
|
||||
unset(self::$adapters[$key]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function get_adapters()
|
||||
{
|
||||
return self::$adapters;
|
||||
}
|
||||
|
||||
// cache
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @return bool
|
||||
*/
|
||||
public function has($key)
|
||||
{
|
||||
return self::$adapter->hasItem(self::$prefix . $key);
|
||||
}
|
||||
|
||||
// truyen 1 tham so - lay binh thuong
|
||||
// truyen 2 tham so tro len - luu cache cho lan sau
|
||||
/**
|
||||
* @param string $key
|
||||
* @param mixed $default
|
||||
* @param array $opt
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($key, $default = null, $opt = [])
|
||||
{
|
||||
$opt += [
|
||||
'expire' => self::$expire,
|
||||
'debug' => false,
|
||||
'save' => true,
|
||||
'save_if' => null, // ?callable
|
||||
];
|
||||
|
||||
if (self::$debug || $opt['debug']) {
|
||||
self::unset(self::$prefix . $key);
|
||||
}
|
||||
|
||||
// get cache
|
||||
$item = self::$adapter->getItem(self::$prefix . $key);
|
||||
|
||||
if ($item->isHit()) {
|
||||
return $item->get();
|
||||
} else {
|
||||
if (is_callable($default)) {
|
||||
$default = call_user_func($default, $opt);
|
||||
}
|
||||
|
||||
if ($opt['save']) {
|
||||
$save = false;
|
||||
|
||||
if (is_callable($opt['save_if'])) {
|
||||
if (call_user_func($opt['save_if'], $default)) {
|
||||
$save = true;
|
||||
}
|
||||
} else {
|
||||
$save = true;
|
||||
}
|
||||
|
||||
if ($save) {
|
||||
self::set($key, $default, $opt['expire']);
|
||||
}
|
||||
}
|
||||
|
||||
return $default;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @param int|null $expire
|
||||
* @return bool
|
||||
*/
|
||||
public function set($key, $value, $expire = null)
|
||||
{
|
||||
$item = self::$adapter->getItem(self::$prefix . $key);
|
||||
|
||||
if ($expire !== null) {
|
||||
$item->expiresAfter($expire);
|
||||
} elseif (self::$expire !== null) {
|
||||
$item->expiresAfter(self::$expire);
|
||||
}
|
||||
|
||||
$item->set($value);
|
||||
return self::$adapter->save($item);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @return bool
|
||||
*/
|
||||
public function unset($key)
|
||||
{
|
||||
return self::$adapter->deleteItem(self::$prefix . $key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $prefix
|
||||
* @return bool
|
||||
*/
|
||||
public function clear($prefix = '')
|
||||
{
|
||||
return self::$adapter->clear($prefix);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
<?php
|
||||
|
||||
namespace Nightmare;
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
if (!function_exists('ndg')) {
|
||||
function ndg(...$vars) {
|
||||
if (PHP_SAPI === 'cli') {
|
||||
var_dump(...$vars);
|
||||
} else {
|
||||
ob_start();
|
||||
var_dump(...$vars);
|
||||
$output = ob_get_clean();
|
||||
|
||||
echo '<pre>';
|
||||
echo htmlspecialchars($output, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
|
||||
echo '</pre>';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('nde')) {
|
||||
function nde(...$vars) {
|
||||
ndg(...$vars);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user