This commit is contained in:
me
2026-07-23 15:29:13 +07:00
commit 9ec08a3e44
36 changed files with 2790 additions and 0 deletions
+6
View File
@@ -0,0 +1,6 @@
.idea/
vendor/
error_log
composer.lock
+31
View File
@@ -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"
}
}
}
+17
View File
@@ -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
View File
@@ -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
View File
@@ -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);
}
}
+21
View File
@@ -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) {}
}
+90
View File
@@ -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) . ';');
}
}
+47
View File
@@ -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;
}
}
+248
View File
@@ -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);
}
}
+27
View File
@@ -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;
}
}
+14
View File
@@ -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);
}
}
+91
View File
@@ -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;
}
}
+50
View File
@@ -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");
}
}
+54
View File
@@ -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
View File
@@ -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'] ?? '';
}
}
+29
View File
@@ -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);
}
}
+7
View File
@@ -0,0 +1,7 @@
<?php
namespace Nightmare\Http;
use Symfony\Component\HttpClient\CurlHttpClient;
class_alias(CurlHttpClient::class, 'Nightmare\Http\Client');
+7
View File
@@ -0,0 +1,7 @@
<?php
namespace Nightmare\Http;
use Symfony\Component\HttpClient\HttpClient;
class_alias(HttpClient::class, 'Nightmare\Http\ClientNative');
+15
View File
@@ -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);
}
}
+40
View File
@@ -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;
}
}
+482
View File
@@ -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;
}
}
+154
View File
@@ -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();
}
}
}
+56
View File
@@ -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));
}
}
+57
View File
@@ -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
View File
@@ -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;
}
}
+79
View File
@@ -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];
}
}
}
+62
View File
@@ -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),
);
}
}
+47
View File
@@ -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
View File
@@ -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;
}
}
+207
View File
@@ -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);
}
}
View File
+207
View File
@@ -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);
}
}
+4
View File
@@ -0,0 +1,4 @@
<?php
namespace Nightmare;
+25
View File
@@ -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);
}
}
View File
View File