first commit.
This commit is contained in:
@@ -0,0 +1,179 @@
|
||||
<?php
|
||||
|
||||
namespace Libs;
|
||||
|
||||
use CurlHandle;
|
||||
|
||||
/**
|
||||
* Aria2
|
||||
*
|
||||
* Library to control aria2c from PHP
|
||||
* using its jsonrpc API.
|
||||
*
|
||||
* @author KJ
|
||||
* @website https://kj2.me
|
||||
* @licence MIT
|
||||
*/
|
||||
class Aria2
|
||||
{
|
||||
protected CurlHandle $ch;
|
||||
protected ?string $token;
|
||||
protected bool $batch = false;
|
||||
protected array $batch_list = [];
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $server
|
||||
* Path to aria2's jsonrpc server.
|
||||
* @param string|null $token
|
||||
* (optional) Access token for aria2c API.
|
||||
*/
|
||||
public function __construct(string $server = 'http://127.0.0.1:6800/jsonrpc', ?string $token = null)
|
||||
{
|
||||
$this->ch = curl_init($server);
|
||||
$this->token = $token;
|
||||
curl_setopt_array($this->ch, [
|
||||
CURLOPT_POST => true,
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_HEADER => false,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
curl_close($this->ch);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows starting a batch call.
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function batch(): static
|
||||
{
|
||||
$this->batch = true;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether it is in a batch call or not.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function inBatch(): bool
|
||||
{
|
||||
return $this->batch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a batch request.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function commit(): mixed
|
||||
{
|
||||
$data = json_encode($this->batch_list);
|
||||
$this->batch = false;
|
||||
$this->batch_list = [];
|
||||
$result = $this->send($data);
|
||||
return json_decode($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a request to aria2c via jsonrpc.
|
||||
*
|
||||
* @param string $data
|
||||
* @return string|bool
|
||||
*/
|
||||
protected function send(string $data): string|bool
|
||||
{
|
||||
curl_setopt($this->ch, CURLOPT_POSTFIELDS, $data);
|
||||
return curl_exec($this->ch);
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic to simplify work :).
|
||||
*
|
||||
* PHP methods are automatically converted into aria2 methods.
|
||||
*
|
||||
* aria2.addUri => Aria2::addUri
|
||||
* aria2.addTorrent => Aria2::addTorrent
|
||||
* aria2.getPeers => Aria2::getPeers
|
||||
* aria2.addMetalink => Aria2::addMetalink
|
||||
* aria2.remove => Aria2::remove
|
||||
* aria2.pause => Aria2::pause
|
||||
* aria2.forcePause => Aria2::forcePause
|
||||
* aria2.pauseAll => Aria2::pauseAll
|
||||
* aria2.forcePauseAll => Aria2::forcePauseAll
|
||||
* aria2.unpause => Aria2::unpause
|
||||
* aria2.unpauseAll => Aria2::unpauseAll
|
||||
* aria2.forceRemove => Aria2::forceRemove
|
||||
* aria2.changePosition => Aria2::changePosition
|
||||
* aria2.tellStatus => Aria2::tellStatus
|
||||
* aria2.getUris => Aria2::getUris
|
||||
* aria2.getFiles => Aria2::getFiles
|
||||
* aria2.getServers => Aria2::getServers
|
||||
* aria2.tellActive => Aria2::tellActive
|
||||
* aria2.tellWaiting => Aria2::tellWaiting
|
||||
* aria2.tellStopped => Aria2::tellStopped
|
||||
* aria2.getOption => Aria2::getOption
|
||||
* aria2.changeUri => Aria2::changeUri
|
||||
* aria2.changeOption => Aria2::changeOption
|
||||
* aria2.getGlobalOption => Aria2::getGlobalOption
|
||||
* aria2.changeGlobalOption => Aria2::changeGlobalOption
|
||||
* aria2.purgeDownloadResult => Aria2::purgeDownloadResult
|
||||
* aria2.removeDownloadResult => Aria2::removeDownloadResult
|
||||
* aria2.getVersion => Aria2::getVersion
|
||||
* aria2.getSessionInfo => Aria2::getSessionInfo
|
||||
* aria2.shutdown => Aria2::shutdown
|
||||
* aria2.forceShutdown => Aria2::forceShutdown
|
||||
* aria2.getGlobalStat => Aria2::getGlobalStat
|
||||
* aria2.saveSession => Aria2::saveSession
|
||||
* system.multicall => Aria2::system_multicall
|
||||
* system.listMethods => Aria2::system_listMethods
|
||||
* system.listNotifications => Aria2::system_listNotifications
|
||||
*
|
||||
* @param array<int,mixed> $arg
|
||||
* @return mixed
|
||||
*/
|
||||
public function __call(string $name, array $arg): mixed
|
||||
{
|
||||
if (!is_null($this->token)) {
|
||||
array_unshift($arg, $this->token);
|
||||
}
|
||||
|
||||
// Allow system methods (the last 3 on the list)
|
||||
if (strpos($name, '_') === false) { // if it doesn't contain underscores, it's an aria2 method command.
|
||||
$name = 'aria2.' . $name;
|
||||
} else {
|
||||
$name = str_replace('_', '.', $name);
|
||||
}
|
||||
|
||||
$data = [
|
||||
'jsonrpc' => '2.0',
|
||||
'id' => '1',
|
||||
'method' => $name,
|
||||
'params' => $arg,
|
||||
];
|
||||
|
||||
// Apply batch call if we are in one
|
||||
if ($this->batch) {
|
||||
$this->batch_list[] = $data;
|
||||
return $this;
|
||||
}
|
||||
|
||||
$data = json_encode($data);
|
||||
$response = $this->send($data);
|
||||
if ($response === false) {
|
||||
trigger_error(curl_error($this->ch));
|
||||
}
|
||||
|
||||
return json_decode($response);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
<?php
|
||||
|
||||
namespace Libs;
|
||||
|
||||
/**
|
||||
* CompreFase - DuckBrain
|
||||
*
|
||||
* Library for CompreFace (https://github.com/exadel-inc/CompreFace/).
|
||||
* Can use the constants COMPREFACE_API and COMPREFACE_KEY.
|
||||
*
|
||||
* @author KJ
|
||||
* @website https://kj2.me
|
||||
* @license MIT
|
||||
*/
|
||||
class CompreFace
|
||||
{
|
||||
private string $apiUrl;
|
||||
private CurlRequest $request;
|
||||
|
||||
/**
|
||||
* __construct
|
||||
*
|
||||
* @param string $apiKey
|
||||
* @param string $apiUrl
|
||||
*/
|
||||
public function __construct(string $apiKey = '', string $apiUrl = '')
|
||||
{
|
||||
if (!defined('COMPREFACE_KEY') && empty($apiKey)) {
|
||||
throw new \Exception('CompreFace API Key is not defined.');
|
||||
}
|
||||
|
||||
if (empty($apiKey)) {
|
||||
$apiKey = COMPREFACE_KEY;
|
||||
}
|
||||
|
||||
if (!empty($apiUrl)) {
|
||||
$this->apiUrl = $apiUrl;
|
||||
} elseif (defined('COMPREFACE_API')) {
|
||||
$this->apiUrl = COMPREFACE_API;
|
||||
} else {
|
||||
$this->apiUrl = 'http://localhost:8000/api/v1/';
|
||||
}
|
||||
|
||||
$this->request = new CurlRequest();
|
||||
$this->request->headers['x-api-key'] = $apiKey;
|
||||
$this->request->headers['Content-Type'] = 'application/json';
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the request's JSON and returns it as Neuron.
|
||||
*
|
||||
* @param mixed $default
|
||||
* Default value to return if the result is not JSON.
|
||||
*/
|
||||
private function parseJSON(mixed $default = [])
|
||||
{
|
||||
$json = json_decode($this->request->body());
|
||||
|
||||
if (json_last_error() === JSON_ERROR_NONE) {
|
||||
return $json;
|
||||
}
|
||||
|
||||
return $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of subjects registered in CompreFace.
|
||||
*/
|
||||
public function subjects()
|
||||
{
|
||||
$this->request->get($this->apiUrl . 'recognition/subjects');
|
||||
|
||||
$response = $this->parseJSON(['subjects' => []]);
|
||||
|
||||
if (isset($response->subjects)) {
|
||||
return $response->subjects;
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a subject.
|
||||
*
|
||||
* @param string $name
|
||||
*/
|
||||
public function addSubject(string $name)
|
||||
{
|
||||
$this->request->post(
|
||||
$this->apiUrl . 'recognition/subjects',
|
||||
json_encode(['subject' => $name])
|
||||
);
|
||||
|
||||
return $this->parseJSON();
|
||||
}
|
||||
|
||||
/**
|
||||
* Renames a subject.
|
||||
*
|
||||
* @param string $name Current name
|
||||
* @param string $newName New name
|
||||
*/
|
||||
public function renameSubject(string $name, string $newName)
|
||||
{
|
||||
$this->request->put(
|
||||
$this->apiUrl . 'recognition/subjects/' . rawurlencode($name),
|
||||
json_encode(['subject' => $newName])
|
||||
);
|
||||
|
||||
return $this->parseJSON();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a subject.
|
||||
*
|
||||
* @param string $name
|
||||
*/
|
||||
public function deleteSubject(string $name)
|
||||
{
|
||||
$this->request->delete(
|
||||
$this->apiUrl . 'recognition/subjects/' . rawurlencode($name)
|
||||
);
|
||||
|
||||
return $this->parseJSON();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all subjects from CompreFace.
|
||||
*/
|
||||
public function deleteAllSubjects()
|
||||
{
|
||||
$this->request->delete(
|
||||
$this->apiUrl . 'recognition/subjects'
|
||||
);
|
||||
|
||||
return $this->parseJSON();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the subject's images.
|
||||
*
|
||||
* @param string $subjectName
|
||||
*/
|
||||
public function subjectImages(string $subjectName)
|
||||
{
|
||||
$this->request->get(
|
||||
$this->apiUrl . 'recognition/faces',
|
||||
['size' => 100, 'subject' => $subjectName]
|
||||
);
|
||||
|
||||
return $this->parseJSON();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an image to the subject.
|
||||
*
|
||||
* @param string $subjectName
|
||||
* @param string $base64_image
|
||||
*/
|
||||
public function addSubjectImage(string $subjectName, string $base64_image)
|
||||
{
|
||||
$this->request->post(
|
||||
$this->apiUrl . 'recognition/faces?subject=' . rawurlencode($subjectName),
|
||||
json_encode(['file' => $base64_image])
|
||||
);
|
||||
|
||||
return $this->parseJSON();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an image from the subject.
|
||||
*
|
||||
* @param string $imageId
|
||||
*/
|
||||
public function deteleSubjectImage(string $imageId)
|
||||
{
|
||||
// CompreFace also allows deleting multiple or deleting all,
|
||||
// but for now I won't add it to this library, as it is not necessary.
|
||||
$this->request->delete(
|
||||
$this->apiUrl . 'recognition/faces/' . rawurlencode($imageId)
|
||||
);
|
||||
|
||||
return $this->parseJSON();
|
||||
}
|
||||
|
||||
/**
|
||||
* Facial recognition of the sent image.
|
||||
*
|
||||
* @param string $base64_image
|
||||
*/
|
||||
public function recognize(string $base64_image)
|
||||
{
|
||||
$this->request->post(
|
||||
$this->apiUrl . 'recognition/recognize',
|
||||
json_encode(['file' => $base64_image])
|
||||
);
|
||||
|
||||
return $this->parseJSON();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the subject exists in CompreFace.
|
||||
*
|
||||
* @param string $name
|
||||
*/
|
||||
public function subjectExist(string $name)
|
||||
{
|
||||
$subject = $this->subjects();
|
||||
return in_array($name, $subject);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
<?php
|
||||
|
||||
namespace Libs;
|
||||
|
||||
/**
|
||||
* CurlRequest - DuckBrain
|
||||
*
|
||||
* Facade for CURL.
|
||||
*
|
||||
* @author KJ
|
||||
* @website https://kj2.me
|
||||
* @licence MIT
|
||||
*/
|
||||
class CurlRequest
|
||||
{
|
||||
public array $headers = [];
|
||||
public array $options = [
|
||||
CURLOPT_SSL_VERIFYPEER => false,
|
||||
CURLOPT_SSL_VERIFYHOST => false,
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLINFO_HEADER_OUT => true,
|
||||
];
|
||||
public int $statusCode = 0;
|
||||
protected string $responseHeaders = '';
|
||||
protected string $responseBody = '';
|
||||
|
||||
/**
|
||||
* Sends the request.
|
||||
*
|
||||
* @param array $options
|
||||
* @return void
|
||||
*/
|
||||
protected function send(array $options): void
|
||||
{
|
||||
$handler = curl_init();
|
||||
|
||||
$headers = [];
|
||||
foreach ($this->headers as $index => $value) {
|
||||
$headers[] = "$index: $value";
|
||||
}
|
||||
|
||||
$options[CURLOPT_HTTPHEADER] = $headers;
|
||||
|
||||
foreach ($this->options as $index => $option) {
|
||||
if (!isset($options[$index])) {
|
||||
$options[$index] = $option;
|
||||
}
|
||||
}
|
||||
|
||||
curl_setopt_array($handler, $options);
|
||||
|
||||
$this->responseBody = curl_exec($handler);
|
||||
$this->responseHeaders = curl_getinfo($handler, CURLINFO_HEADER_OUT);
|
||||
$this->statusCode = curl_getinfo($handler, CURLINFO_HTTP_CODE);
|
||||
|
||||
// throw new Exception('Error al realizar la solicitud. '. curl_error($handler));
|
||||
|
||||
curl_close($handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the request using the GET method.
|
||||
*
|
||||
* @param string $url
|
||||
* @param array $args
|
||||
*
|
||||
* @return CurlRequest
|
||||
*/
|
||||
public function get(string $url, array $args = []): CurlRequest
|
||||
{
|
||||
$this->send([
|
||||
CURLOPT_URL => $url . '?' . http_build_query($args),
|
||||
CURLOPT_POST => false,
|
||||
CURLOPT_PUT => false,
|
||||
]);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the request using the POST method.
|
||||
*
|
||||
* @param string $url
|
||||
* @param string $fields
|
||||
*
|
||||
* @return CurlRequest
|
||||
*/
|
||||
public function post(string $url, string $fields = ''): CurlRequest
|
||||
{
|
||||
$this->send([
|
||||
CURLOPT_URL => $url,
|
||||
CURLOPT_POSTFIELDS => $fields,
|
||||
]);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the request using the PUT method.
|
||||
*
|
||||
* @param string $url
|
||||
* @param string $fields
|
||||
*
|
||||
* @return CurlRequest
|
||||
*/
|
||||
public function put(string $url, string $fields = ''): CurlRequest
|
||||
{
|
||||
$this->send([
|
||||
CURLOPT_URL => $url,
|
||||
CURLOPT_CUSTOMREQUEST => 'PUT',
|
||||
CURLOPT_POSTFIELDS => $fields,
|
||||
]);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the request using the PATCH method.
|
||||
*
|
||||
* @param string $url
|
||||
* @param string $fields
|
||||
*
|
||||
* @return CurlRequest
|
||||
*/
|
||||
public function patch(string $url, string $fields = ''): CurlRequest
|
||||
{
|
||||
$this->send([
|
||||
CURLOPT_URL => $url,
|
||||
CURLOPT_CUSTOMREQUEST => 'PATCH',
|
||||
CURLOPT_POSTFIELDS => $fields,
|
||||
]);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the request using the DELETE method.
|
||||
*
|
||||
* @param string $url
|
||||
* @param string $fields
|
||||
*
|
||||
* @return CurlRequest
|
||||
*/
|
||||
public function delete(string $url, string $fields = ''): CurlRequest
|
||||
{
|
||||
$this->send([
|
||||
CURLOPT_URL => $url,
|
||||
CURLOPT_CUSTOMREQUEST => 'DELETE',
|
||||
CURLOPT_POSTFIELDS => $fields,
|
||||
]);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the response headers.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function headers(): string
|
||||
{
|
||||
return $this->responseHeaders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the response body.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function body(): string
|
||||
{
|
||||
return $this->responseBody;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
<?php
|
||||
|
||||
namespace Libs;
|
||||
|
||||
/**
|
||||
* PHP Proxy - DuckBrain
|
||||
*
|
||||
* Proxy is a library to create a PHP proxy.
|
||||
* It allows controlling the headers that will be returned to the client,
|
||||
* in addition to placing filters on the resulting HTML code.
|
||||
*
|
||||
* @author KJ
|
||||
* @website https://kj2.me
|
||||
* @licence MIT
|
||||
*/
|
||||
class Proxy
|
||||
{
|
||||
public static $proxied_headers = [
|
||||
'Set-Cookie',
|
||||
'Content-Type',
|
||||
'Cookie',
|
||||
'Location',
|
||||
];
|
||||
public static $proxy_base_url_canonical = '/';
|
||||
public static $destination_host = SOURCE_URL;
|
||||
protected static $filters = [];
|
||||
|
||||
/**
|
||||
* Adds a callable (AKA filter) that will receive the content
|
||||
* and should return a string.
|
||||
*
|
||||
* @param callable $cb
|
||||
* Function that will modify the content.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function add_filter(callable $cb): void
|
||||
{
|
||||
static::$filters[] = $cb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the filters configured with add_filter.
|
||||
*
|
||||
* @param string $content
|
||||
* Content on which the filters will be applied.
|
||||
*
|
||||
* @return mixed
|
||||
* It would be correct to return a string, but
|
||||
* since the filters might not return correctly,
|
||||
* to avoid a design error, we specify that it returns mixed.
|
||||
*/
|
||||
protected static function apply_filters(string $content): mixed
|
||||
{
|
||||
foreach (static::$filters as $filter) {
|
||||
$content = call_user_func($filter, $content);
|
||||
}
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the proxy process.
|
||||
*
|
||||
* @param string|null $proxy_request_uri
|
||||
* The address to which the proxy will be applied.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function run(?string $proxy_request_uri = null): void
|
||||
{
|
||||
// Get the URI if not defined
|
||||
if (is_null($proxy_request_uri)) {
|
||||
$proxy_request_uri = substr($_SERVER['REQUEST_URI'], strlen(static::$proxy_base_url_canonical));
|
||||
} elseif (substr($proxy_request_uri, 0, 1) == '/') {
|
||||
$proxy_request_uri = substr($proxy_request_uri, 1);
|
||||
}
|
||||
|
||||
// Generate the final URL
|
||||
$proxy_request_url = static::$destination_host . $proxy_request_uri;
|
||||
|
||||
// cURL initialization
|
||||
$ch = curl_init();
|
||||
|
||||
curl_setopt($ch, CURLOPT_URL, $proxy_request_url);
|
||||
curl_setopt($ch, CURLOPT_AUTOREFERER, 1);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||||
curl_setopt($ch, CURLOPT_HEADER, 1);
|
||||
curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:'));
|
||||
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
|
||||
|
||||
// Capture client cookies
|
||||
$hdrs = [];
|
||||
if (isset($_SERVER['HTTP_COOKIE'])) {
|
||||
$hdrs[] = "Cookie: " . $_SERVER['HTTP_COOKIE'];
|
||||
}
|
||||
|
||||
// Capture client browser (User-Agent)
|
||||
if (isset($_SERVER['HTTP_USER_AGENT'])) {
|
||||
$hdrs[] = "User-Agent: " . $_SERVER['HTTP_USER_AGENT'];
|
||||
}
|
||||
|
||||
// Add captured headers
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $hdrs);
|
||||
|
||||
// Capture all client headers
|
||||
$hdrs = [];
|
||||
foreach (\getallheaders() as $name => $value) {
|
||||
$hdrs[] = "$name: $value";
|
||||
}
|
||||
|
||||
// Add captured headers to the request
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $hdrs);
|
||||
|
||||
// Add POST parameters
|
||||
if (sizeof($_POST) > 0) {
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($_POST));
|
||||
}
|
||||
|
||||
// Execute the request
|
||||
$res = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
|
||||
// Parse the response
|
||||
list($headers, $body) = explode("\r\n\r\n", $res, 2);
|
||||
$headers = str_replace(static::$destination_host, '/', $headers);
|
||||
|
||||
$headers = explode("\r\n", $headers);
|
||||
$hs = [];
|
||||
|
||||
foreach ($headers as $header) {
|
||||
if (false !== strpos($header, ': ')) {
|
||||
list($h, $v) = explode(': ', $header);
|
||||
$hs[$h][] = $v;
|
||||
} else {
|
||||
$header1 = $header;
|
||||
}
|
||||
}
|
||||
|
||||
// Define headers in the client
|
||||
list($proto, $code, $text) = explode(' ', $header1);
|
||||
header($_SERVER['SERVER_PROTOCOL'] . ' ' . $code . ' ' . $text);
|
||||
|
||||
foreach (static::$proxied_headers as $hname) {
|
||||
if (isset($hs[$hname])) {
|
||||
foreach ($hs[$hname] as $v) {
|
||||
if ($hname === 'Set-Cookie') {
|
||||
header($hname . ": " . $v, false);
|
||||
} else {
|
||||
header($hname . ": " . $v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
die(static::apply_filters($body));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user