Commit 3e0246fa by BANice

修改异常记录表

parent 3ff47aa1
......@@ -3,7 +3,11 @@
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/vendor/composer" />
<excludeFolder url="file://$MODULE_DIR$/vendor/guzzlehttp/guzzle" />
<excludeFolder url="file://$MODULE_DIR$/vendor/guzzlehttp/promises" />
<excludeFolder url="file://$MODULE_DIR$/vendor/guzzlehttp/psr7" />
<excludeFolder url="file://$MODULE_DIR$/vendor/monolog/monolog" />
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/http-message" />
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/log" />
<excludeFolder url="file://$MODULE_DIR$/vendor/workerman/gateway-worker" />
<excludeFolder url="file://$MODULE_DIR$/vendor/workerman/mysql" />
......
......@@ -8,6 +8,10 @@
<path value="$PROJECT_DIR$/vendor/workerman/mysql" />
<path value="$PROJECT_DIR$/vendor/workerman/workerman" />
<path value="$PROJECT_DIR$/vendor/composer" />
<path value="$PROJECT_DIR$/vendor/psr/http-message" />
<path value="$PROJECT_DIR$/vendor/guzzlehttp/guzzle" />
<path value="$PROJECT_DIR$/vendor/guzzlehttp/psr7" />
<path value="$PROJECT_DIR$/vendor/guzzlehttp/promises" />
</include_path>
</component>
<component name="PhpProjectSharedConfiguration" php_language_level="7.2" />
......
......@@ -10,6 +10,7 @@ namespace Application;
use Lib\Log;
use Lib\log\DeviceLog;
use Lib\log\LogRecord;
use Lib\Request;
use Lib\Response;
......@@ -142,15 +143,25 @@ class Controller
}
/**
* todo 一次性写入日志
*/
public function __destruct()
public function log()
{
if (count($this->logRecords) != 0) {
}
if ($this->headerCtrl != '00') {
$log = new DeviceLog($_SESSION['gateway_mac'] ? $_SESSION['gateway_mac'] : 'null');
$log->setRequest($this->message);
$log->setResponse($this->response->getResponseMessage());
$log->log();
}
}
......@@ -179,7 +190,7 @@ class Controller
$start += $length;
$this->plc +=$length;
$this->plc += $length;
}
......
......@@ -12,8 +12,11 @@ namespace Application\Controller;
use Application\Controller;
use Application\Model\GatewayModel;
use Application\Model\PortModel;
use Application\Model\StationModel;
use GatewayWorker\Lib\Gateway;
use Lib\Log;
use Lib\port\Port;
use Lib\redis\RedisKey;
class AccessController extends Controller
{
......@@ -38,22 +41,37 @@ class AccessController extends Controller
public function access()
{
Log::debug('请求入网');
$gatewayModel = new GatewayModel();
$mac = $this->get('mac');
$gateway = $gatewayModel->getColumns(['id','station_id'], " mac_address = '$mac' ");
$gateway = $gatewayModel->getColumns(['id', 'station_id'], " mac_address = '$mac' ");
Log::debug('gateway_info', $gateway);
if (count($gateway) !== 0) {
$gatewayId = $gateway['id'];
$redis = \Events::getRedis();
$redis->zAdd(RedisKey::GATEWAY_STATE, 1, $gatewayId);
Gateway::bindUid($this->clientId, $mac);
$_SESSION['gateway_id'] = $gatewayId;
$_SESSION['station_id'] = $gateway['station_id'];
$stationModel = new StationModel();
$stationName = $stationModel->getColumn('name', 'id = ' . $gateway['station_id']);
$_SESSION['station_name'] = $stationName;
$portModel = new PortModel();
//网关id下所有的口子mac地址和id
......@@ -61,18 +79,34 @@ class AccessController extends Controller
if (count($portMacId) !== 0) { //网关下的口子mac和id缓存到session中
$redis = \Events::getRedis();
$redis->multi(2);
$portMacIdHash = [];
//网关下的端口id和mac注入到session当中,静态缓存
foreach ($portMacId as $item) {
$_SESSION['port_mac_id'][$item['device_mac']] = $item['id'];
$portMacIdHash[$item['device_mac']] = $item['id'];
}
$redis->hMset(RedisKey::PORT_MAC_ID, $portMacIdHash);
$redis->hMset(RedisKey::PORT_ID_MAC, array_flip($portMacIdHash));
$redis->exec();
unset($portMacIdHash);
}
$sessionId = '';
for ($i = 0; $i < 4; $i++) {
$hex = sprintf('%02x',rand(0, 255));
$hex = sprintf('%02x', rand(0, 255));
$sessionId .= $hex;
}
......@@ -95,6 +129,10 @@ class AccessController extends Controller
public function syncPort()
{
Log::debug('端口同步', $this->getRequest()->getParameters());
Log::debug($this->message);
$startLogicNum = $this->get('start_num');
$startLogicNumDec = hexdec($startLogicNum);
......@@ -117,18 +155,27 @@ class AccessController extends Controller
$portModel = new PortModel();
$i = 0;
$portMacId = isset($_SESSION['port_mac_id']) ? $_SESSION['port_mac_id'] : [];
var_dump($portMacId);
$port = new port();
$portIdState = [];
$i = 0;
$redis = \Events::getRedis();
$redis->multi(2);
foreach ($macLogicArray as $mac => $logic)//将端口状态和端口逻辑地址更新至数据库中
{
if (isset($portMacId[$mac])) {
$portId = $portMacId[$mac];
$redis->hSet(RedisKey::PORT_ID_LOGIC_HASH, $portId, (int)$logic);
$redis->hSet(sprintf(RedisKey::GATEWAY_PORT_LOGIC_ID_HASH, $_SESSION['gateway_id']), (int)$logic, $portId);
}
$portModel->update([
......@@ -136,23 +183,21 @@ class AccessController extends Controller
'logic_num' => $logic,
], 'device_mac = ' . "'$mac'");
if(isset($portMacId[$mac]))
{
if (isset($portMacId[$mac])) {
$portIdState[$portMacId[$mac]] = $stateArray[$i];
}
$i++;
}
var_dump($portIdState);
$redis->exec();
$port->setPortState($portIdState); //改变口子状态
if(isset($_SESSION['port_mac_id'])) {
$portMacId = $_SESSION['port_mac_id'];
if (isset($_SESSION['port_mac_id'])) {
$portMacId = $_SESSION['port_mac_id'];
}
......@@ -196,7 +241,7 @@ class AccessController extends Controller
return array_map(function ($hex) {
return hexdec($hex);
return (int)hexdec($hex);
}, $state);
}
......
......@@ -11,6 +11,7 @@ namespace Application\Controller;
use Application\Controller;
use Lib\Aes;
use Lib\Log;
class CertifyController extends Controller
{
......@@ -27,6 +28,9 @@ class CertifyController extends Controller
*/
public function certify()
{
Log::debug('平台认证',$this->getRequest()->getParameters());
$nonce = $this->getNonce();
$mac =$this->getRequest()->get('mac');
......
......@@ -10,6 +10,7 @@ namespace Application\Controller;
use Application\Controller;
use Lib\Log;
class HeartController extends Controller
{
......@@ -25,8 +26,7 @@ class HeartController extends Controller
$time = sprintf('%08x',time());
var_dump($time);
Log::debug($time);
$this->response->send('00',$time);
......
<?php
/**
* Created by PhpStorm.
* User: banice
* Date: 2018/6/13
* Time: 上午10:19
*/
namespace Application\Controller;
use Application\Controller;
use Application\Model\ConfigModel;
use Lib\Log;
class SettingController extends Controller
{
public function setting()
{
$configModel = new ConfigModel();
$config = $configModel->getIdConfigValue();
$idConfigValue = [];
foreach ($config as $item) {
$idConfigValue[$item['id']] = $item['config_value'];
}
Log::debug('config', $idConfigValue);
$invertalTime = $idConfigValue['5'];
$getPriceConfig = $idConfigValue['6'];
$powerUpperLimit = $idConfigValue['1'];
$powerSaturateInvertalTime = $idConfigValue['7'];
$extraTime = $idConfigValue['8'];
$powerLowerLimit = 5;
$detectTime = 5;
$afterFormat = $this->adaptor([
[$invertalTime, 4],
[$getPriceConfig, 2],
[$powerUpperLimit, 4],
[$powerSaturateInvertalTime, 2],
[$extraTime, 2],
[$powerLowerLimit, 2],
[$detectTime, 2],
]);
Log::debug('afterFormat', $afterFormat);
$this->response->send('0a', implode($afterFormat));
}
/**
* @param array $data
* @return array
*/
private function adaptor(array $data)
{
$afterFormat = [];
foreach ($data as $item) {
array_push($afterFormat, sprintf('%0' . $item[1] . 'x', $item[0]));
}
return $afterFormat;
}
}
......@@ -41,7 +41,6 @@ class Events
if (Env::has('REDIS_PASSWORD')) {
var_dump(Env::get('REDIS_PASSWORD'));
static::$redis->auth(Env::get('REDIS_PASSWORD'));
}
......@@ -53,7 +52,8 @@ class Events
static::$db = new Connection(Env::get('DB_HOST'), Env::get('DB_PORT'), Env::get('DB_USER'), Env::get('DB_PASSWORD'), Env::get('DB_NAME'));
} catch (Exception $exception) {
var_dump($exception->getMessage());
Log::error($exception->getMessage());
}
......@@ -65,7 +65,8 @@ class Events
Log::debug('connect', [
'time' => date('H:i:s'),
'time' => date('H:i:s'),
'clientId' => $clientId,
]);
......@@ -75,18 +76,22 @@ class Events
{
var_dump($message);
$crc = substr($message, -2);
$makeCrc = sprintf('%08x', (Crc::crc(substr($message, 0, -2))));
if ($crc != substr($makeCrc, 0, 2)) {
if ($crc != mb_strtoupper(substr($makeCrc, 0, 2))) {
Log::error('crc 错误');
Gateway::closeClient($clientId);
} else {
$command = substr($message, 6, 2);
$route = Api::getRoute($command);
......@@ -115,7 +120,10 @@ class Events
try {
Gateway::closeCurrentClient();
} catch (Exception $e) {
Log::error($e->getMessage());
}
}
}
}
......@@ -124,12 +132,20 @@ class Events
$controller->$method();
if ($controller instanceof \Application\Controller) {
$controller->log();
}
unset($controller);
}
}
}
......@@ -139,22 +155,79 @@ class Events
*/
public static function onClose($clientId)
{
//fixme 网关离线将往下所有的口子全部设置为离线
// 网关离线将往下所有的口子全部设置为离线
if (isset($_SESSION['gateway_id']) === true) {
Log::info('gateway_id(' . $_SESSION['gateway_id'] . ')' . 'disconnect');
$redis = Events::getRedis();
$redis->zAdd(\Lib\redis\RedisKey::GATEWAY_STATE, 0, $_SESSION['gateway_id']);
if(!isset($_SESSION['port_mac_id']))
} else {
Log::info(isset($_SESSION['gateway_mac']) ? $_SESSION['gateway_mac'] : '');
Log::info('gatway disconnect');
}
if (isset($_SESSION['gateway_mac']) === true) {
$gatewayMac = $_SESSION['gateway_mac'];
$log = new \Lib\log\DeviceLog($gatewayMac);
$log->setType('state');
$log->log();
$clientIds = Gateway::getClientIdByUid($gatewayMac);
foreach ($clientIds as $clientId) {
Gateway::closeClient($clientId);
}
}
$_SESSION['certified'] = false;
if (!isset($_SESSION['port_mac_id']))
return;
$portMacIdArray = $_SESSION['port_mac_id'];
$portMacIdArray = $_SESSION['port_mac_id'];
if(isset($portMacIdArray))
{
if (isset($portMacIdArray)) {
$port = new \Lib\port\Port();
Log::debug('close 设置离线口子', $portMacIdArray);
$port->offline(array_values($portMacIdArray));
}
try {
$exceptionModel = new \Application\Model\ExceptionModel();
$gatewayId = $_SESSION['gateway_id'];
$insert = ['message' => '网关离线', 'gateway_id' => $gatewayId, 'type' => 1,'created_at' => date('Y-m-d H:i:s')];
if(isset($_SESSION['station_id']))
{
$insert['station_id'] = $_SESSION['station_id'];
}
$exceptionModel->insertRow($insert);
} catch (Exception $exception) {
Log::error($exception->getMessage());
}
}
public static function getRedis()
......
......@@ -16,7 +16,15 @@ class AuthMiddleware extends Middleware
public function handle($clientId, $message): bool
{
return isset($_SESSION['certified']);
$result = isset($_SESSION['certified']);
if($result === true)
{
$result = $_SESSION['certified'] === true;
}
return $result;
}
......
......@@ -117,6 +117,4 @@ class Model
}
\ No newline at end of file
<?php
/**
* Created by PhpStorm.
* User: banice
* Date: 2018/6/13
* Time: 上午10:28
*/
namespace Application\Model;
use Application\Model;
class ConfigModel extends Model
{
protected $table = 'configs';
public function getIdConfigValue()
{
return $this->db->query('SELECT id , config_value FROM '.$this->table);
}
//最大功率限制
public function getPowerUpperLimit()
{
return $this->getColumn('config_value','id = 1');
}
//数据上报间隔时间
public function getInvertalTime()
{
return $this->getColumn('config_value','id = 5');
}
//获取计价配置时间间隔
public function getPriceConfig()
{
return $this->getColumn('config_value','id = 6');
}
//充满自停的功率检测此时
public function getPowerSaturateInvertalTime()
{
return $this->getColumn('config_value','id = 7');
}
//充满自停额外的供电时间
public function getExtraTime()
{
return $this->getColumn('config_value','id = 8');
}
}
\ No newline at end of file
<?php
/**
* Created by PhpStorm.
* User: banice
* Date: 2018/6/20
* Time: 下午2:54
*/
namespace Application\Model;
use Application\Model;
class ExceptionModel extends Model
{
protected $table = 'exception';
}
\ No newline at end of file
<?php
/**
* Created by PhpStorm.
* User: banice
* Date: 2018/6/5
* Time: 下午8:55
*/
namespace Application\Model;
use Application\Model;
class OrderExceptionModel extends Model
{
protected $table = 'wx_charger_orders_exception';
}
\ No newline at end of file
<?php
/**
* Created by PhpStorm.
* User: banice
* Date: 2018/6/2
* Time: 下午2:23
*/
namespace Application\Model;
use Application\Model;
class StationModel extends Model
{
protected $table = 'stations';
}
\ No newline at end of file
......@@ -15,9 +15,12 @@ use Monolog\Logger;
/**
*
* @method static debug($info, $context = [])
* @method static warn($info, $context = [])
* @method static alert($info, $context = [])
* @method static error($info, $context = [])
* @method static info($info, $context = [])
*
*
* Class Log
* @package Lib
......@@ -65,7 +68,11 @@ class Log
public static function __callStatic($name, $arguments)
{
return call_user_func_array([static::$log,$name],$arguments);
$gatewayMac = isset($_SESSION['gateway_mac']) ? $_SESSION['gateway_mac'] : 'null mac';
$arguments[0] = "[$gatewayMac] -> " . $arguments[0];
return call_user_func_array([static::$log, $name], $arguments);
}
......
......@@ -51,6 +51,11 @@ class Response
private $controller;
/**
* @var string
*/
private $responseMessage = '';
/**
* Response constructor.
* @param Controller $controller
*/
......@@ -75,7 +80,10 @@ class Response
$this->headerFlag = $this->controller->isEncrypt() ? '05' : '04';
$this->length = sprintf('%04x',(7+strlen($data)/2 + 1));
$this->length = sprintf('%04x',(8+strlen($data)/2 ));
Log::debug('send-length'.$this->length);
Gateway::sendToClient($this->controller->getClientId(),$this->organize());
......@@ -96,13 +104,36 @@ class Response
$crc = substr(sprintf('%08x',Crc::crc($exceptCrc)),0,2);
var_dump('message:'.PHP_EOL.$exceptCrc.$crc);
if(strlen($exceptCrc)%2 != 0)
{
Log::error('length wrogn');
}
Log::debug('response'.$exceptCrc);
return $this->responseMessage = $exceptCrc.$crc;
}
return $exceptCrc.$crc;
/**
* @return string
*/
public function getResponseMessage(): string
{
return $this->responseMessage;
}
/**
* @param string $responseMessage
*/
public function setResponseMessage(string $responseMessage): void
{
$this->responseMessage = $responseMessage;
}
}
......
<?php
/**
* Created by PhpStorm.
* User: banice
* Date: 2018/6/14
* Time: 下午5:16
*/
namespace Lib\api\message;
class ChargerExceedMessage extends MessageData
{
/**
* @var string
*/
protected $templateId = 'IDrdzTNQ7t4uRXkP0SkuwW10WH77A_CIgYFiJykXJ0utU';
/**
* @var string
*/
private $first = '尊敬的用户,你的爱车功率过大,本次充电已结束
';
/**
* @var string
*/
private $remark = '温馨提示:电瓶车的功率超出了充电口所允许的最大充电功率,您可以在公众号后台留言或直接拨打客服热线进行咨询';
/**
* @var string
*/
private $startTime = '';
/**
* @var string
*/
private $chargerTime = '';
/**
* @var string
*/
private $endTime = '';
public function getPushDataJson(): string
{
return json_encode([
'first' => [
'value' => $this->first,
'color' => '#333',
],
'keyword1' => [
'value' => $this->startTime,
'color' => '#333',
],
'keyword2' => [
'value' => $this->chargerTime,
'color' => '#333',
],
'keyword3' => [
'value' => $this->chargerTime,
'color' => '#333',
],
'keyword4' => [
'value' => $this->endTime,
'color' => '#333',
],
'remark' => [
'value' => $this->remark,
'color' => '#333',
],
]);
}
/**
* @return string
*/
public function getRemark(): string
{
return $this->remark;
}
/**
* @param string $remark
*/
public function setRemark(string $remark): void
{
$this->remark = $remark;
}
/**
* @return string
*/
public function getStartTime(): string
{
return $this->startTime;
}
/**
* @param string $startTime
*/
public function setStartTime(string $startTime): void
{
$this->startTime = $startTime;
}
/**
* @return string
*/
public function getChargerTime(): string
{
return $this->chargerTime;
}
/**
* @param string $chargerTime
*/
public function setChargerTime(string $chargerTime): void
{
$this->chargerTime = $chargerTime;
}
/**
* @return string
*/
public function getEndTime(): string
{
return $this->endTime;
}
/**
* @param string $endTime
*/
public function setEndTime(string $endTime): void
{
$this->endTime = $endTime;
}
}
\ No newline at end of file
<?php
/**
* Created by PhpStorm.
* User: banice
* Date: 2018/6/4
* Time: 下午3:56
*/
namespace Lib\api\message;
use Application\Model\OrderModel;
use Lib\Log;
class ChargerFinishMessage extends MessageData
{
protected $templateId = 'f0DDXSxvRTbHyzkCnwnYijtgteFTdfdUR7J8REwTYJ8';
private $first = '亲爱的用户,您的爱车已经完成充电啦';
/**
* @var string
*/
private $endTime = '';
/**
* @var string
*/
private $chargerPlc = '';
/**
* @var string
*/
private $chargerTime;
/**
* @var int
*/
private $orderAmount;
/**
* @var string
*/
private $remark = '感谢你的使用';
/**
* @var int
*/
/**
* @return string
*/
public function getPushDataJson(): string
{
return json_encode([
'first' => [
'value' => $this->first,
'color' => '#333',
],
'keyword1' => [
'value' => $this->endTime,
'color' => '#333',
],
'keyword2' => [
'value' => $this->chargerPlc,
'color' => '#333',
],
'keyword3' => [
'value' => $this->chargerTime.' 分',
'color' => '#333',
],
'keyword4' => [
'value' => $this->orderAmount.' ¥',
'color' => '#333',
],
'remark' => [
'value' => $this->remark,
'color' => '#333',
],
]);
}
/**
* @return string
*/
public function getFirst(): string
{
return $this->first;
}
/**
* @param string $first
*/
public function setFirst(string $first): void
{
$this->first = $first;
}
/**
* @return string
*/
public function getEndTime(): string
{
return $this->endTime;
}
/**
* @param string $endTime
*/
public function setEndTime(string $endTime): void
{
$this->endTime = $endTime;
}
/**
* @return string
*/
public function getChargerPlc(): string
{
return $this->chargerPlc;
}
/**
* @param string $chargerPlc
*/
public function setChargerPlc(string $chargerPlc): void
{
$this->chargerPlc = $chargerPlc;
}
/**
* @return string
*/
public function getChargerTime(): string
{
return $this->chargerTime;
}
/**
* @param string $chargerTime
*/
public function setChargerTime(string $chargerTime): void
{
$this->chargerTime = $chargerTime;
}
/**
* @return int
*/
public function getOrderAmount(): int
{
return $this->orderAmount;
}
/**
* @param int $orderAmount
*/
public function setOrderAmount(int $orderAmount): void
{
$this->orderAmount = $orderAmount;
}
/**
* @return string
*/
public function getRemark(): string
{
return $this->remark;
}
/**
* @param string $remark
*/
public function setRemark(string $remark): void
{
$this->remark = $remark;
}
/**
* @return int
*/
public function getUserId(): int
{
return $this->userId;
}
/**
* @param int $userId
*/
public function setUserId(int $userId): void
{
$this->userId = $userId;
}
}
\ No newline at end of file
<?php
/**
* Created by PhpStorm.
* User: banice
* Date: 2018/6/14
* Time: 下午2:19
*/
namespace Lib\api\message;
class ChargerRefundMessage extends MessageData
{
protected $templateId = '0al-a6kkNsdqFyXPEe97m4jjtbfOXjEC3eCjEsMHJdw';
private $first = '超时未插入插头,已取消订单,退款稍后送达,请注意查收';
/**
* @var string
*/
private $outTradeNo = '';
/**
* @var string
*/
private $orderInfo = '';
/**
* @var string
*/
private $orderFee = '';
private $remark = '温馨提示:超时关闭此次交易,支付金额会在1个工作日内退回您的余额或零钱,请注意查看,若未收到请联系我们的客服为您处理。若为充电口异常,请您及时更换至其它充电口充电
';
/**
* @return string
*/
public function getPushDataJson(): string
{
// TODO: Implement getPushDataJson() method.
return json_encode([
'first' => [
'value' => $this->first,
'color' => '#333',
],
'keyword1' => [
'value' => $this->outTradeNo,
'color' => '#333',
],
'keyword2' => [
'value' => $this->orderInfo,
'color' => '#333',
],
'keyword3' => [
'value' => '¥'.$this->orderFee ,
'color' => '#333',
],
'remark' => [
'value' => $this->remark,
'color' => '#333',
],
]);
}
public function getUserId(): int
{
return $this->userId;
}
/**
* @return string
*/
public function getTemplateId(): string
{
return $this->templateId;
}
/**
* @param mixed $templateId
*/
public function setTemplateId($templateId): void
{
$this->templateId = $templateId;
}
/**
* @return string
*/
public function getFirst(): string
{
return $this->first;
}
/**
* @param string $first
*/
public function setFirst(string $first): void
{
$this->first = $first;
}
/**
* @return string
*/
public function getOutTradeNo(): string
{
return $this->outTradeNo;
}
/**
* @param string $outTradeNo
*/
public function setOutTradeNo(string $outTradeNo): void
{
$this->outTradeNo = $outTradeNo;
}
/**
* @return string
*/
public function getOrderInfo(): string
{
return $this->orderInfo;
}
/**
* @param string $orderInfo
*/
public function setOrderInfo(string $orderInfo): void
{
$this->orderInfo = $orderInfo;
}
/**
* @return string
*/
public function getOrderFee(): string
{
return $this->orderFee;
}
/**
* @param string $orderFee
*/
public function setOrderFee(string $orderFee): void
{
$this->orderFee = $orderFee;
}
/**
* @return string
*/
public function getRemark(): string
{
return $this->remark;
}
/**
* @param string $remark
*/
public function setRemark(string $remark): void
{
$this->remark = $remark;
}
}
\ No newline at end of file
<?php
/**
* Created by PhpStorm.
* User: banice
* Date: 2018/6/2
* Time: 上午11:01
*/
namespace Lib\api\message;
class ChargerStartMessage extends MessageData
{
protected $templateId = 'L9SEWl3X73v3PBYHtFBZlTlJeBMdO9DDNIwRgHX6SrY';
private $first = '充电已经开始,请注意接收消息';
private $startTime;
private $address;
private $amount;
public function __construct()
{
$this->startTime = date('Y-m-d H:i:s');
}
/**
* @return string
*/
public function getPushDataJson(): string
{
return json_encode([
'first' => [
'value' => $this->first,
'color' => '#333',
],
'keyword1' => [
'value' => $this->startTime,
'color' => '#333',
],
'keyword2' => [
'value' => $this->address,
'color' => '#333'
],
'keyword3' => [
'value' => $this->amount,
'color' => '#333'
],
'remark' => [
'value' => '感谢你的使用',
'color' => '#333'
],
]);
}
public function getUserId(): int
{
// TODO: Implement getUserId() method.
}
/**
* @return string
*/
public function getFirst(): string
{
return $this->first;
}
/**
* @param string $first
*/
public function setFirst(string $first): void
{
$this->first = $first;
}
/**
* @return mixed
*/
public function getStartTime()
{
return $this->startTime;
}
/**
* @param mixed $startTime
*/
public function setStartTime($startTime): void
{
$this->startTime = $startTime;
}
/**
* @return mixed
*/
public function getAddress()
{
return $this->address;
}
/**
* @param mixed $address
*/
public function setAddress($address): void
{
$this->address = $address;
}
/**
* @return mixed
*/
public function getAmount()
{
return $this->amount;
}
/**
* @param mixed $amount
*/
public function setAmount($amount): void
{
$this->amount = $amount;
}
}
\ No newline at end of file
<?php
/**
* Created by PhpStorm.
* User: banice
* Date: 2018/6/2
* Time: 上午11:03
*/
namespace Lib\api\message;
abstract class MessageData
{
protected $templateId;
/**
* @var int
*/
protected $userId = 1;
abstract public function getPushDataJson(): string;
/**
* @return mixed
*/
public function getTemplateId()
{
return $this->templateId;
}
/**
* @param mixed $templateId
*/
public function setTemplateId($templateId): void
{
$this->templateId = $templateId;
}
protected function getUserId(): int
{
return $this->userId;
}
public function setUserId(int $userId): void
{
$this->userId = $userId;
}
}
\ No newline at end of file
<?php
/**
* Created by PhpStorm.
* User: banice
* Date: 2018/6/5
* Time: 上午9:48
*/
namespace Lib\api\message;
class PortShedMessage extends MessageData
{
/**
* @var string
*/
protected $templateId = 'C0LvfETe-1rCR_IhOydDGPTUwwYkrWZxgfwMsETrhw8';
/**
* @var string
*/
private $first = '尊敬的用户,充电端未检测到插头,请您在%s分钟内接入
';
/**
* @var string
*/
private $portName = '';
/**
* @var string
*/
private $stationName = '';
/**
* @var string
*/
private $time = '';
/**
* @var string
*/
private $remark = '超时将关闭此次交易哦,支付金额会在1个工作日内退回您的余额或零钱,请注意查看,若未收到请联系我们的客服为您处理。若为充电口异常,请您及时更换至其它充电口充电';
/**
* @var int
*/
private $waitingTime = 3;
public function __construct() {
$this->time = date('Y-m-d H:i:s');
}
public function getUserId(): int
{
// TODO: Implement getUserId() method.
}
/**
* @return string
*/
public function getPushDataJson(): string
{
$this->first = sprintf($this->first,$this->waitingTime);
return json_encode([
'first' => [
'value' => $this->first,
'color' => '#333',
],
'keyword1' => [
'value' => $this->stationName . "($this->portName)",
'color' => '#333',
],
'keyword2' => [
'value' => $this->time,
'color' => '#333',
],
'remark' => [
'value' => $this->remark,
'color' => '#333',
],
]);
// TODO: Implement getPushDataJson() method.
}
/**
* @return string
*/
public function getFirst(): string
{
return $this->first;
}
/**
* @param string $first
*/
public function setFirst(string $first): void
{
$this->first = $first;
}
/**
* @return string
*/
public function getPortName(): string
{
return $this->portName;
}
/**
* @param string $portName
*/
public function setPortName(string $portName): void
{
$this->portName = $portName;
}
/**
* @return string
*/
public function getStationName(): string
{
return $this->stationName;
}
/**
* @param string $stationName
*/
public function setStationName(string $stationName): void
{
$this->stationName = $stationName;
}
/**
* @return string
*/
public function getTime(): string
{
return $this->time;
}
/**
* @param string $time
*/
public function setTime(string $time): void
{
$this->time = $time;
}
/**
* @return string
*/
public function getRemark(): string
{
return $this->remark;
}
/**
* @param string $remark
*/
public function setRemark(string $remark): void
{
$this->remark = $remark;
}
}
\ No newline at end of file
<?php
/**
* Created by PhpStorm.
* User: banice
* Date: 2018/6/2
* Time: 上午11:01
*/
namespace Lib\api\message;
use GuzzleHttp\Client;
use Lib\Log;
class Push
{
const URI = 'https://cdzback2.test.senthink.com';
const PATH = 'api/v1/wechatMessage';
/**
* @param MessageData $messageData
* @param string $userId
* @return bool
* @throws \GuzzleHttp\Exception\GuzzleException
*/
public function push(MessageData $messageData,string $userId)
{
$client = new Client([
'base_uri' => self::URI
]);
$response = $client->request('POST',self::PATH,[
'form_params' => [
'userId' => $userId,
'templateId' => $messageData->getTemplateId(),
'data' => $messageData->getPushDataJson(),
],
'http_errors' => false,
]);
if($response->getStatusCode() === 200)
{
Log::debug('发送模版消息'.$messageData->getTemplateId(),json_decode($response->getBody(),true));
}
Log::debug($response->getStatusCode());
return $response->getStatusCode() === 200;
}
}
\ No newline at end of file
<?php
/**
* Created by PhpStorm.
* User: banice
* Date: 2018/6/5
* Time: 上午11:23
*/
namespace Lib\log;
use Lib\Log;
class DeviceLog
{
/**
* 日志队列
*/
const DEVICE_LOG_LIST = 'cdz:device:log:list';
/**
* 日志时间戳有序集合
*/
const DEVICE_LOG_TIMESTAMP_ZSET = 'cdz:device:log:timestamp:zset';
/**
* @var \Redis
*/
private $redis;
/**
* @var string
*/
private $type = 'data';
/**
* @var string
*/
private $request ='';
/**
* @var string
*/
private $logListKey = '';
/**
* @var string
*/
private $timeZsetKey = '';
/**
* @var string
*/
private $response = '';
public function __construct(string $gatewayMac) {
$this->redis = \Events::getRedis();
$this->logListKey = self::DEVICE_LOG_LIST.':'.$gatewayMac;
$this->timeZsetKey = self::DEVICE_LOG_TIMESTAMP_ZSET.':'.$gatewayMac;
}
public function log()
{
$this->redis->multi(\Redis::PIPELINE);
$this->redis->lPush($this->logListKey,json_encode([
'type' => $this->type,
'request' => $this->request,
'response' => $this->response,
'time' => date('Y-m-d H:i:s')
]));
$date = date('Y-m-d 00:00:00');
$date = date('Y-m-d H:i:s',strtotime($date.'- 14 day'));
$time = time();
$this->redis->zAdd($this->timeZsetKey,0,$time);
$this->redis->exec();
//$time -= 60*60*24;
$time = strtotime($date);
$plc = $this->redis->zRangeByLex($this->timeZsetKey,'[0','['.$time);
$expiredCount = count($plc);
if($expiredCount !== 0)
{
Log::debug('过期日志时间戳',[$plc]);
Log::debug('存在过期日志',compact('expiredCount'));
$this->redis->multi(2);
$this->redis->zRemRangeByLex($this->timeZsetKey,'[0','['.$time);
$this->redis->lTrim($this->logListKey,0,0-$expiredCount);
$this->redis->exec();
}
}
/**
* @return string
*/
public function getRequest(): string
{
return $this->request;
}
/**
* @param string $request
*/
public function setRequest(string $request): void
{
$this->request = $request;
}
/**
* @return string
*/
public function getResponse(): string
{
return $this->response;
}
/**
* @param string $response
*/
public function setResponse(string $response): void
{
$this->response = $response;
}
/**
* @return string
*/
public function getType(): string
{
return $this->type;
}
/**
* @param string $type
*/
public function setType(string $type): void
{
$this->type = $type;
}
}
......@@ -9,7 +9,9 @@
namespace Lib\port;
use Lib\Log;
use Lib\redis\RedisKey;
use Lib\state\StateCode;
class Port
{
......@@ -49,6 +51,17 @@ class Port
}
/**
* @param $portId
* @return float
*/
public function getState($portId)
{
return $this->redis->zScore(RedisKey::PORT_STATE_ZSET,$portId);
}
public function pipe()
{
$this->redis = $this->redis->multi(\Redis::PIPELINE);
......@@ -72,7 +85,7 @@ class Port
/**
* 设置端口的状态
* 端口zset中,gateway的端口zset
* 端口zset中,gateway的端口zset,station的端口zset
* @param array $portIdState
*/
public function setPortState(array $portIdState)
......@@ -81,6 +94,8 @@ class Port
foreach ($portIdState as $id => $state) {
Log::debug($id.'-'.$state);
array_push($tmp, $state);
array_push($tmp, $id);
......@@ -111,11 +126,13 @@ class Port
*/
public function online(array $portId)
{
Log::debug('online');
$tmp = [RedisKey::PORT_STATE_ZSET];
foreach ($portId as $item) {
array_push($tmp, 1);
array_push($tmp, StateCode::PORT_ONLINE);
array_push($tmp, $item);
......@@ -140,17 +157,55 @@ class Port
}
/**
* 设置口子当前使用者id
* @param int $userId
*/
public function setUsingUserId(int $userId)
{
$this->redis->zAdd(RedisKey::PORT_USING_USER_ID,$userId,$this->id);
}
/**
* 设置口子当前订单id
* @param int $orderId
*/
public function setUsingOrderId(int $orderId)
{
$this->redis->zAdd(RedisKey::PORT_USING_ORDER_ID,$orderId,$this->id);
}
/**
* 端口充电结束释放口子redis处理
*/
public function freePort()
{
//todo 口子充电结束,释放口子,删除正在使用的订单号和用户id,口子状态修改为1。
$this->redis->hDel(RedisKey::PORT_USING_ORDER_ID,$this->id);
$this->redis->zRem(RedisKey::PORT_USING_USER_ID,$this->id);
$this->setPortState([$this->id=> StateCode::PORT_ONLINE]);
}
/**
* 端口id下线
* @param array $portId
*/
public function offline(array $portId)
{
$tmp = [RedisKey::PORT_STATE_ZSET];
Log::debug('offline');
$tmp = [RedisKey::PORT_STATE_ZSET];
foreach ($portId as $item) {
array_push($tmp, 0);
array_push($tmp, StateCode::PORT_OFFLINE);
array_push($tmp, $item);
......@@ -176,4 +231,137 @@ class Port
$this->redis->exec();
}
/**
* @return mixed
*/
public function getMac()
{
return $this->mac;
}
/**
* @param mixed $mac
*/
public function setMac($mac): void
{
$this->mac = $mac;
}
/**
* @return mixed
*/
public function getId()
{
return $this->id;
}
/**
* @param mixed $id
*/
public function setId($id): void
{
$this->id = $id;
}
/**
* @return mixed
*/
public function getLogic()
{
return $this->logic;
}
/**
* @param mixed $logic
*/
public function setLogic($logic): void
{
$this->logic = $logic;
}
/**
* @return mixed
*/
public function getGatewayId()
{
return $this->gatewayId;
}
/**
* @param mixed $gatewayId
*/
public function setGatewayId($gatewayId): void
{
$this->gatewayId = $gatewayId;
}
/**
* @return mixed
*/
public function getGatewayMac()
{
return $this->gatewayMac;
}
/**
* @param mixed $gatewayMac
*/
public function setGatewayMac($gatewayMac): void
{
$this->gatewayMac = $gatewayMac;
}
/**
* @return \Redis
*/
public function getRedis(): \Redis
{
return $this->redis;
}
/**
* @param \Redis $redis
*/
public function setRedis(\Redis $redis): void
{
$this->redis = $redis;
}
/**
* 获取当前口子正在使用的用户id,没有则返回0
*
* @param \Redis $redis
* @param int $portId
* @return int
*/
public function getPortUsingId(\Redis $redis,int $portId) : int
{
$result = $redis->zScore(RedisKey::PORT_USING_USER_ID,$portId);
return isset($result) ? $result : 0;
}
public function getPortUsingOrderId(\Redis $redis ,int $portId) : int
{
$result = $redis->hGet(RedisKey::PORT_USING_ORDER_ID,$portId);
return isset($result) ? $result : 0;
}
/**
* @return string
*/
public function getIdByLogic()
{
$redis = \Events::getRedis();
return $redis->hGet(sprintf(RedisKey::GATEWAY_PORT_LOGIC_ID_HASH,$_SESSION['gateway_id']),$this->logic);
}
}
\ No newline at end of file
......@@ -23,7 +23,7 @@ class RedisKey
//端口id和逻辑地址的hash
const PORT_ID_LOGIC_HASH = 'port:id_logic:hash';
const GATEWAY_PORT_LOGIC_ID_HASH = ':port:logic_id_hash';
const GATEWAY_PORT_LOGIC_ID_HASH = "gateway:%s:port:logic_id_hash";
......@@ -34,5 +34,17 @@ class RedisKey
const STATION_PORT_STATE = 'station:port:state:';
const PORT_USING_ORDER_ID = 'port:using_order_id';
const PORT_USING_USER_ID = 'port:using_user_id';
const WX_USER_ID_OPENID_HASH ='cdz:wx_users:id_openid:hash';
const GATEWAY_STATE = 'cdz:gateway_state:zset';
const PORT_ID_MAC = 'cdz:port:id_mac:hash';
const PORT_MAC_ID = 'cdz:port:mac_id:hash';
}
\ No newline at end of file
<?php
/**
* Created by PhpStorm.
* User: banice
* Date: 2018/6/5
* Time: 下午5:22
*/
namespace Lib\state;
class StateCode
{
const PORT_OFFLINE = 10;
const PORT_ONLINE = 11;
const PORT_CHARGER = 12;
const PORT_EXCEPTION = 13;
const PORT_SHED = 14;
const CHARGER_FAIL = 21;
const CHARGER_SHED = 22;
const CHARGER_SUCCESS = 23;
const FINISH_TIME_END = 30;
const FINISH_REMOTE = 31;
const FINISH_SHED = 32;
const FINISH_FULL = 33;
const FINISH_EXCEED = 34;
const FINISH_FAIL = 35;
const FINISH_CHARGER = 36;
}
\ No newline at end of file
<?php
/**
* Created by PhpStorm.
* User: banice
* Date: 2018/6/5
* Time: 上午10:24
*/
namespace Lib\wx;
use Lib\redis\RedisKey;
class User
{
/**
* @var int
*/
private $userId;
/**
* @var string
*/
private $openid;
public function getOpenIdByUserId() : bool
{
$redis = \Events::getRedis();
$result = $redis->hGet(RedisKey::WX_USER_ID_OPENID_HASH,$this->userId);
$this->openid = $result;
return isset($result);
}
/**
* @return string
*/
public function getOpenid(): string
{
return $this->openid;
}
/**
* @param string $openid
*/
public function setOpenid(string $openid): void
{
$this->openid = $openid;
}
/**
* @return int
*/
public function getUserId(): int
{
return $this->userId;
}
/**
* @param int $userId
*/
public function setUserId(int $userId): void
{
$this->userId = $userId;
}
}
\ No newline at end of file
......@@ -21,7 +21,7 @@ class Api
public static function boot()
{
static::add('00','HeartController@heart');
static::add('00','HeartController@heart',[new AuthMiddleware(),new HasMacMiddleware()]);
static::add('01','CertifyController@certify');
......@@ -31,6 +31,8 @@ class Api
static::add('04','PowerController@charger',[new AuthMiddleware(),new HasMacMiddleware()]);
static::add('05','PowerController@stop',[new AuthMiddleware(),new HasMacMiddleware()]);
static::add('08','PortController@online',[new AuthMiddleware(),new HasMacMiddleware()]);
static::add('09','PortController@offline',[new AuthMiddleware(),new HasMacMiddleware()]);
......@@ -39,7 +41,11 @@ class Api
static::add('17','PowerController@onePower',[new AuthMiddleware(),new HasMacMiddleware()]);
static::add('0b','PortController@portState',[new AuthMiddleware(),new HasMacMiddleware()]);
static::add('0B','PortController@portState',[new AuthMiddleware(),new HasMacMiddleware()]);
static::add('0A','SettingController@setting');
}
......
......@@ -2,7 +2,8 @@
"require": {
"workerman/gateway-worker": "^3.0",
"workerman/mysql": "^1.0",
"monolog/monolog": "^1.23"
"monolog/monolog": "^1.23",
"guzzlehttp/guzzle": "^6.3"
},
"autoload": {
"psr-4": {
......
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "fa4e68da7636d16dd347ebf62881d69a",
"content-hash": "5e3071f271d42e2e0ca4014c09b4a61e",
"packages": [
{
"name": "guzzlehttp/guzzle",
"version": "6.3.3",
"source": {
"type": "git",
"url": "https://github.com/guzzle/guzzle.git",
"reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/407b0cb880ace85c9b63c5f9551db498cb2d50ba",
"reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba",
"shasum": ""
},
"require": {
"guzzlehttp/promises": "^1.0",
"guzzlehttp/psr7": "^1.4",
"php": ">=5.5"
},
"require-dev": {
"ext-curl": "*",
"phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0",
"psr/log": "^1.0"
},
"suggest": {
"psr/log": "Required for using the Log middleware"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "6.3-dev"
}
},
"autoload": {
"files": [
"src/functions_include.php"
],
"psr-4": {
"GuzzleHttp\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
}
],
"description": "Guzzle is a PHP HTTP client library",
"homepage": "http://guzzlephp.org/",
"keywords": [
"client",
"curl",
"framework",
"http",
"http client",
"rest",
"web service"
],
"time": "2018-04-22T15:46:56+00:00"
},
{
"name": "guzzlehttp/promises",
"version": "v1.3.1",
"source": {
"type": "git",
"url": "https://github.com/guzzle/promises.git",
"reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646",
"reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646",
"shasum": ""
},
"require": {
"php": ">=5.5.0"
},
"require-dev": {
"phpunit/phpunit": "^4.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.4-dev"
}
},
"autoload": {
"psr-4": {
"GuzzleHttp\\Promise\\": "src/"
},
"files": [
"src/functions_include.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
}
],
"description": "Guzzle promises library",
"keywords": [
"promise"
],
"time": "2016-12-20T10:07:11+00:00"
},
{
"name": "guzzlehttp/psr7",
"version": "1.4.2",
"source": {
"type": "git",
"url": "https://github.com/guzzle/psr7.git",
"reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/f5b8a8512e2b58b0071a7280e39f14f72e05d87c",
"reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c",
"shasum": ""
},
"require": {
"php": ">=5.4.0",
"psr/http-message": "~1.0"
},
"provide": {
"psr/http-message-implementation": "1.0"
},
"require-dev": {
"phpunit/phpunit": "~4.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.4-dev"
}
},
"autoload": {
"psr-4": {
"GuzzleHttp\\Psr7\\": "src/"
},
"files": [
"src/functions_include.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
},
{
"name": "Tobias Schultze",
"homepage": "https://github.com/Tobion"
}
],
"description": "PSR-7 message implementation that also provides common utility methods",
"keywords": [
"http",
"message",
"request",
"response",
"stream",
"uri",
"url"
],
"time": "2017-03-20T17:10:46+00:00"
},
{
"name": "monolog/monolog",
"version": "1.23.0",
"source": {
......@@ -85,6 +266,56 @@
"time": "2017-06-19T01:22:40+00:00"
},
{
"name": "psr/http-message",
"version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-message.git",
"reference": "f6561bf28d520154e4b0ec72be95418abe6d9363"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363",
"reference": "f6561bf28d520154e4b0ec72be95418abe6d9363",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Http\\Message\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interface for HTTP messages",
"homepage": "https://github.com/php-fig/http-message",
"keywords": [
"http",
"http-message",
"psr",
"psr-7",
"request",
"response"
],
"time": "2016-08-06T14:39:51+00:00"
},
{
"name": "psr/log",
"version": "1.0.2",
"source": {
......
......@@ -29,7 +29,7 @@ require_once __DIR__ . '/vendor/autoload.php';
function exceptionHandle($exception)
{
$logger = new \Monolog\Logger('error');
$logger = new \Monolog\Logger('./storage/log/error');
$logger->pushHandler(new \Monolog\Handler\RotatingFileHandler('./storage/log/error', 30));
......
......@@ -379,9 +379,9 @@ class ClassLoader
$subPath = substr($subPath, 0, $lastPos);
$search = $subPath.'\\';
if (isset($this->prefixDirsPsr4[$search])) {
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
foreach ($this->prefixDirsPsr4[$search] as $dir) {
$length = $this->prefixLengthsPsr4[$first][$search];
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
if (file_exists($file = $dir . $pathEnd)) {
return $file;
}
}
......
<?php
// autoload_files.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'c964ee0ededf28c96ebd9db5099ef910' => $vendorDir . '/guzzlehttp/promises/src/functions_include.php',
'a0edc8309cc5e1d60e3047b5df6b7052' => $vendorDir . '/guzzlehttp/psr7/src/functions_include.php',
'37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php',
);
......@@ -10,8 +10,12 @@ return array(
'Workerman\\' => array($vendorDir . '/workerman/workerman'),
'Route\\' => array($baseDir . '/Route'),
'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'),
'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-message/src'),
'Monolog\\' => array($vendorDir . '/monolog/monolog/src/Monolog'),
'Lib\\' => array($baseDir . '/Lib'),
'GuzzleHttp\\Psr7\\' => array($vendorDir . '/guzzlehttp/psr7/src'),
'GuzzleHttp\\Promise\\' => array($vendorDir . '/guzzlehttp/promises/src'),
'GuzzleHttp\\' => array($vendorDir . '/guzzlehttp/guzzle/src'),
'GatewayWorker\\' => array($vendorDir . '/workerman/gateway-worker/src'),
'Application\\' => array($baseDir . '/Application'),
);
......@@ -47,6 +47,24 @@ class ComposerAutoloaderInit2caa2c3ca5dbe5c7cb007a3a9b1ddec8
$loader->register(true);
if ($useStaticLoader) {
$includeFiles = Composer\Autoload\ComposerStaticInit2caa2c3ca5dbe5c7cb007a3a9b1ddec8::$files;
} else {
$includeFiles = require __DIR__ . '/autoload_files.php';
}
foreach ($includeFiles as $fileIdentifier => $file) {
composerRequire2caa2c3ca5dbe5c7cb007a3a9b1ddec8($fileIdentifier, $file);
}
return $loader;
}
}
function composerRequire2caa2c3ca5dbe5c7cb007a3a9b1ddec8($fileIdentifier, $file)
{
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
require $file;
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
}
}
......@@ -6,6 +6,12 @@ namespace Composer\Autoload;
class ComposerStaticInit2caa2c3ca5dbe5c7cb007a3a9b1ddec8
{
public static $files = array (
'c964ee0ededf28c96ebd9db5099ef910' => __DIR__ . '/..' . '/guzzlehttp/promises/src/functions_include.php',
'a0edc8309cc5e1d60e3047b5df6b7052' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/functions_include.php',
'37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php',
);
public static $prefixLengthsPsr4 = array (
'W' =>
array (
......@@ -19,6 +25,7 @@ class ComposerStaticInit2caa2c3ca5dbe5c7cb007a3a9b1ddec8
'P' =>
array (
'Psr\\Log\\' => 8,
'Psr\\Http\\Message\\' => 17,
),
'M' =>
array (
......@@ -30,6 +37,9 @@ class ComposerStaticInit2caa2c3ca5dbe5c7cb007a3a9b1ddec8
),
'G' =>
array (
'GuzzleHttp\\Psr7\\' => 16,
'GuzzleHttp\\Promise\\' => 19,
'GuzzleHttp\\' => 11,
'GatewayWorker\\' => 14,
),
'A' =>
......@@ -55,6 +65,10 @@ class ComposerStaticInit2caa2c3ca5dbe5c7cb007a3a9b1ddec8
array (
0 => __DIR__ . '/..' . '/psr/log/Psr/Log',
),
'Psr\\Http\\Message\\' =>
array (
0 => __DIR__ . '/..' . '/psr/http-message/src',
),
'Monolog\\' =>
array (
0 => __DIR__ . '/..' . '/monolog/monolog/src/Monolog',
......@@ -63,6 +77,18 @@ class ComposerStaticInit2caa2c3ca5dbe5c7cb007a3a9b1ddec8
array (
0 => __DIR__ . '/../..' . '/Lib',
),
'GuzzleHttp\\Psr7\\' =>
array (
0 => __DIR__ . '/..' . '/guzzlehttp/psr7/src',
),
'GuzzleHttp\\Promise\\' =>
array (
0 => __DIR__ . '/..' . '/guzzlehttp/promises/src',
),
'GuzzleHttp\\' =>
array (
0 => __DIR__ . '/..' . '/guzzlehttp/guzzle/src',
),
'GatewayWorker\\' =>
array (
0 => __DIR__ . '/..' . '/workerman/gateway-worker/src',
......
Copyright (c) 2011-2018 Michael Dowling, https://github.com/mtdowling <mtdowling@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Guzzle, PHP HTTP client
=======================
[![Latest Version](https://img.shields.io/github/release/guzzle/guzzle.svg?style=flat-square)](https://github.com/guzzle/guzzle/releases)
[![Build Status](https://img.shields.io/travis/guzzle/guzzle.svg?style=flat-square)](https://travis-ci.org/guzzle/guzzle)
[![Total Downloads](https://img.shields.io/packagist/dt/guzzlehttp/guzzle.svg?style=flat-square)](https://packagist.org/packages/guzzlehttp/guzzle)
Guzzle is a PHP HTTP client that makes it easy to send HTTP requests and
trivial to integrate with web services.
- Simple interface for building query strings, POST requests, streaming large
uploads, streaming large downloads, using HTTP cookies, uploading JSON data,
etc...
- Can send both synchronous and asynchronous requests using the same interface.
- Uses PSR-7 interfaces for requests, responses, and streams. This allows you
to utilize other PSR-7 compatible libraries with Guzzle.
- Abstracts away the underlying HTTP transport, allowing you to write
environment and transport agnostic code; i.e., no hard dependency on cURL,
PHP streams, sockets, or non-blocking event loops.
- Middleware system allows you to augment and compose client behavior.
```php
$client = new \GuzzleHttp\Client();
$res = $client->request('GET', 'https://api.github.com/repos/guzzle/guzzle');
echo $res->getStatusCode();
// 200
echo $res->getHeaderLine('content-type');
// 'application/json; charset=utf8'
echo $res->getBody();
// '{"id": 1420053, "name": "guzzle", ...}'
// Send an asynchronous request.
$request = new \GuzzleHttp\Psr7\Request('GET', 'http://httpbin.org');
$promise = $client->sendAsync($request)->then(function ($response) {
echo 'I completed! ' . $response->getBody();
});
$promise->wait();
```
## Help and docs
- [Documentation](http://guzzlephp.org/)
- [Stack Overflow](http://stackoverflow.com/questions/tagged/guzzle)
- [Gitter](https://gitter.im/guzzle/guzzle)
## Installing Guzzle
The recommended way to install Guzzle is through
[Composer](http://getcomposer.org).
```bash
# Install Composer
curl -sS https://getcomposer.org/installer | php
```
Next, run the Composer command to install the latest stable version of Guzzle:
```bash
php composer.phar require guzzlehttp/guzzle
```
After installing, you need to require Composer's autoloader:
```php
require 'vendor/autoload.php';
```
You can then later update Guzzle using composer:
```bash
composer.phar update
```
## Version Guidance
| Version | Status | Packagist | Namespace | Repo | Docs | PSR-7 | PHP Version |
|---------|------------|---------------------|--------------|---------------------|---------------------|-------|-------------|
| 3.x | EOL | `guzzle/guzzle` | `Guzzle` | [v3][guzzle-3-repo] | [v3][guzzle-3-docs] | No | >= 5.3.3 |
| 4.x | EOL | `guzzlehttp/guzzle` | `GuzzleHttp` | [v4][guzzle-4-repo] | N/A | No | >= 5.4 |
| 5.x | Maintained | `guzzlehttp/guzzle` | `GuzzleHttp` | [v5][guzzle-5-repo] | [v5][guzzle-5-docs] | No | >= 5.4 |
| 6.x | Latest | `guzzlehttp/guzzle` | `GuzzleHttp` | [v6][guzzle-6-repo] | [v6][guzzle-6-docs] | Yes | >= 5.5 |
[guzzle-3-repo]: https://github.com/guzzle/guzzle3
[guzzle-4-repo]: https://github.com/guzzle/guzzle/tree/4.x
[guzzle-5-repo]: https://github.com/guzzle/guzzle/tree/5.3
[guzzle-6-repo]: https://github.com/guzzle/guzzle
[guzzle-3-docs]: http://guzzle3.readthedocs.org/en/latest/
[guzzle-5-docs]: http://guzzle.readthedocs.org/en/5.3/
[guzzle-6-docs]: http://guzzle.readthedocs.org/en/latest/
{
"name": "guzzlehttp/guzzle",
"type": "library",
"description": "Guzzle is a PHP HTTP client library",
"keywords": ["framework", "http", "rest", "web service", "curl", "client", "HTTP client"],
"homepage": "http://guzzlephp.org/",
"license": "MIT",
"authors": [
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
}
],
"require": {
"php": ">=5.5",
"guzzlehttp/psr7": "^1.4",
"guzzlehttp/promises": "^1.0"
},
"require-dev": {
"ext-curl": "*",
"phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0",
"psr/log": "^1.0"
},
"autoload": {
"files": ["src/functions_include.php"],
"psr-4": {
"GuzzleHttp\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"GuzzleHttp\\Tests\\": "tests/"
}
},
"suggest": {
"psr/log": "Required for using the Log middleware"
},
"extra": {
"branch-alias": {
"dev-master": "6.3-dev"
}
}
}
<?php
namespace GuzzleHttp;
use GuzzleHttp\Promise\PromiseInterface;
use GuzzleHttp\Exception\GuzzleException;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\UriInterface;
/**
* Client interface for sending HTTP requests.
*/
interface ClientInterface
{
const VERSION = '6.3.3';
/**
* Send an HTTP request.
*
* @param RequestInterface $request Request to send
* @param array $options Request options to apply to the given
* request and to the transfer.
*
* @return ResponseInterface
* @throws GuzzleException
*/
public function send(RequestInterface $request, array $options = []);
/**
* Asynchronously send an HTTP request.
*
* @param RequestInterface $request Request to send
* @param array $options Request options to apply to the given
* request and to the transfer.
*
* @return PromiseInterface
*/
public function sendAsync(RequestInterface $request, array $options = []);
/**
* Create and send an HTTP request.
*
* Use an absolute path to override the base path of the client, or a
* relative path to append to the base path of the client. The URL can
* contain the query string as well.
*
* @param string $method HTTP method.
* @param string|UriInterface $uri URI object or string.
* @param array $options Request options to apply.
*
* @return ResponseInterface
* @throws GuzzleException
*/
public function request($method, $uri, array $options = []);
/**
* Create and send an asynchronous HTTP request.
*
* Use an absolute path to override the base path of the client, or a
* relative path to append to the base path of the client. The URL can
* contain the query string as well. Use an array to provide a URL
* template and additional variables to use in the URL template expansion.
*
* @param string $method HTTP method
* @param string|UriInterface $uri URI object or string.
* @param array $options Request options to apply.
*
* @return PromiseInterface
*/
public function requestAsync($method, $uri, array $options = []);
/**
* Get a client configuration option.
*
* These options include default request options of the client, a "handler"
* (if utilized by the concrete client), and a "base_uri" if utilized by
* the concrete client.
*
* @param string|null $option The config option to retrieve.
*
* @return mixed
*/
public function getConfig($option = null);
}
<?php
namespace GuzzleHttp\Cookie;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
/**
* Cookie jar that stores cookies as an array
*/
class CookieJar implements CookieJarInterface
{
/** @var SetCookie[] Loaded cookie data */
private $cookies = [];
/** @var bool */
private $strictMode;
/**
* @param bool $strictMode Set to true to throw exceptions when invalid
* cookies are added to the cookie jar.
* @param array $cookieArray Array of SetCookie objects or a hash of
* arrays that can be used with the SetCookie
* constructor
*/
public function __construct($strictMode = false, $cookieArray = [])
{
$this->strictMode = $strictMode;
foreach ($cookieArray as $cookie) {
if (!($cookie instanceof SetCookie)) {
$cookie = new SetCookie($cookie);
}
$this->setCookie($cookie);
}
}
/**
* Create a new Cookie jar from an associative array and domain.
*
* @param array $cookies Cookies to create the jar from
* @param string $domain Domain to set the cookies to
*
* @return self
*/
public static function fromArray(array $cookies, $domain)
{
$cookieJar = new self();
foreach ($cookies as $name => $value) {
$cookieJar->setCookie(new SetCookie([
'Domain' => $domain,
'Name' => $name,
'Value' => $value,
'Discard' => true
]));
}
return $cookieJar;
}
/**
* @deprecated
*/
public static function getCookieValue($value)
{
return $value;
}
/**
* Evaluate if this cookie should be persisted to storage
* that survives between requests.
*
* @param SetCookie $cookie Being evaluated.
* @param bool $allowSessionCookies If we should persist session cookies
* @return bool
*/
public static function shouldPersist(
SetCookie $cookie,
$allowSessionCookies = false
) {
if ($cookie->getExpires() || $allowSessionCookies) {
if (!$cookie->getDiscard()) {
return true;
}
}
return false;
}
/**
* Finds and returns the cookie based on the name
*
* @param string $name cookie name to search for
* @return SetCookie|null cookie that was found or null if not found
*/
public function getCookieByName($name)
{
// don't allow a null name
if ($name === null) {
return null;
}
foreach ($this->cookies as $cookie) {
if ($cookie->getName() !== null && strcasecmp($cookie->getName(), $name) === 0) {
return $cookie;
}
}
}
public function toArray()
{
return array_map(function (SetCookie $cookie) {
return $cookie->toArray();
}, $this->getIterator()->getArrayCopy());
}
public function clear($domain = null, $path = null, $name = null)
{
if (!$domain) {
$this->cookies = [];
return;
} elseif (!$path) {
$this->cookies = array_filter(
$this->cookies,
function (SetCookie $cookie) use ($path, $domain) {
return !$cookie->matchesDomain($domain);
}
);
} elseif (!$name) {
$this->cookies = array_filter(
$this->cookies,
function (SetCookie $cookie) use ($path, $domain) {
return !($cookie->matchesPath($path) &&
$cookie->matchesDomain($domain));
}
);
} else {
$this->cookies = array_filter(
$this->cookies,
function (SetCookie $cookie) use ($path, $domain, $name) {
return !($cookie->getName() == $name &&
$cookie->matchesPath($path) &&
$cookie->matchesDomain($domain));
}
);
}
}
public function clearSessionCookies()
{
$this->cookies = array_filter(
$this->cookies,
function (SetCookie $cookie) {
return !$cookie->getDiscard() && $cookie->getExpires();
}
);
}
public function setCookie(SetCookie $cookie)
{
// If the name string is empty (but not 0), ignore the set-cookie
// string entirely.
$name = $cookie->getName();
if (!$name && $name !== '0') {
return false;
}
// Only allow cookies with set and valid domain, name, value
$result = $cookie->validate();
if ($result !== true) {
if ($this->strictMode) {
throw new \RuntimeException('Invalid cookie: ' . $result);
} else {
$this->removeCookieIfEmpty($cookie);
return false;
}
}
// Resolve conflicts with previously set cookies
foreach ($this->cookies as $i => $c) {
// Two cookies are identical, when their path, and domain are
// identical.
if ($c->getPath() != $cookie->getPath() ||
$c->getDomain() != $cookie->getDomain() ||
$c->getName() != $cookie->getName()
) {
continue;
}
// The previously set cookie is a discard cookie and this one is
// not so allow the new cookie to be set
if (!$cookie->getDiscard() && $c->getDiscard()) {
unset($this->cookies[$i]);
continue;
}
// If the new cookie's expiration is further into the future, then
// replace the old cookie
if ($cookie->getExpires() > $c->getExpires()) {
unset($this->cookies[$i]);
continue;
}
// If the value has changed, we better change it
if ($cookie->getValue() !== $c->getValue()) {
unset($this->cookies[$i]);
continue;
}
// The cookie exists, so no need to continue
return false;
}
$this->cookies[] = $cookie;
return true;
}
public function count()
{
return count($this->cookies);
}
public function getIterator()
{
return new \ArrayIterator(array_values($this->cookies));
}
public function extractCookies(
RequestInterface $request,
ResponseInterface $response
) {
if ($cookieHeader = $response->getHeader('Set-Cookie')) {
foreach ($cookieHeader as $cookie) {
$sc = SetCookie::fromString($cookie);
if (!$sc->getDomain()) {
$sc->setDomain($request->getUri()->getHost());
}
if (0 !== strpos($sc->getPath(), '/')) {
$sc->setPath($this->getCookiePathFromRequest($request));
}
$this->setCookie($sc);
}
}
}
/**
* Computes cookie path following RFC 6265 section 5.1.4
*
* @link https://tools.ietf.org/html/rfc6265#section-5.1.4
*
* @param RequestInterface $request
* @return string
*/
private function getCookiePathFromRequest(RequestInterface $request)
{
$uriPath = $request->getUri()->getPath();
if ('' === $uriPath) {
return '/';
}
if (0 !== strpos($uriPath, '/')) {
return '/';
}
if ('/' === $uriPath) {
return '/';
}
if (0 === $lastSlashPos = strrpos($uriPath, '/')) {
return '/';
}
return substr($uriPath, 0, $lastSlashPos);
}
public function withCookieHeader(RequestInterface $request)
{
$values = [];
$uri = $request->getUri();
$scheme = $uri->getScheme();
$host = $uri->getHost();
$path = $uri->getPath() ?: '/';
foreach ($this->cookies as $cookie) {
if ($cookie->matchesPath($path) &&
$cookie->matchesDomain($host) &&
!$cookie->isExpired() &&
(!$cookie->getSecure() || $scheme === 'https')
) {
$values[] = $cookie->getName() . '='
. $cookie->getValue();
}
}
return $values
? $request->withHeader('Cookie', implode('; ', $values))
: $request;
}
/**
* If a cookie already exists and the server asks to set it again with a
* null value, the cookie must be deleted.
*
* @param SetCookie $cookie
*/
private function removeCookieIfEmpty(SetCookie $cookie)
{
$cookieValue = $cookie->getValue();
if ($cookieValue === null || $cookieValue === '') {
$this->clear(
$cookie->getDomain(),
$cookie->getPath(),
$cookie->getName()
);
}
}
}
<?php
namespace GuzzleHttp\Cookie;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
/**
* Stores HTTP cookies.
*
* It extracts cookies from HTTP requests, and returns them in HTTP responses.
* CookieJarInterface instances automatically expire contained cookies when
* necessary. Subclasses are also responsible for storing and retrieving
* cookies from a file, database, etc.
*
* @link http://docs.python.org/2/library/cookielib.html Inspiration
*/
interface CookieJarInterface extends \Countable, \IteratorAggregate
{
/**
* Create a request with added cookie headers.
*
* If no matching cookies are found in the cookie jar, then no Cookie
* header is added to the request and the same request is returned.
*
* @param RequestInterface $request Request object to modify.
*
* @return RequestInterface returns the modified request.
*/
public function withCookieHeader(RequestInterface $request);
/**
* Extract cookies from an HTTP response and store them in the CookieJar.
*
* @param RequestInterface $request Request that was sent
* @param ResponseInterface $response Response that was received
*/
public function extractCookies(
RequestInterface $request,
ResponseInterface $response
);
/**
* Sets a cookie in the cookie jar.
*
* @param SetCookie $cookie Cookie to set.
*
* @return bool Returns true on success or false on failure
*/
public function setCookie(SetCookie $cookie);
/**
* Remove cookies currently held in the cookie jar.
*
* Invoking this method without arguments will empty the whole cookie jar.
* If given a $domain argument only cookies belonging to that domain will
* be removed. If given a $domain and $path argument, cookies belonging to
* the specified path within that domain are removed. If given all three
* arguments, then the cookie with the specified name, path and domain is
* removed.
*
* @param string $domain Clears cookies matching a domain
* @param string $path Clears cookies matching a domain and path
* @param string $name Clears cookies matching a domain, path, and name
*
* @return CookieJarInterface
*/
public function clear($domain = null, $path = null, $name = null);
/**
* Discard all sessions cookies.
*
* Removes cookies that don't have an expire field or a have a discard
* field set to true. To be called when the user agent shuts down according
* to RFC 2965.
*/
public function clearSessionCookies();
/**
* Converts the cookie jar to an array.
*
* @return array
*/
public function toArray();
}
<?php
namespace GuzzleHttp\Cookie;
/**
* Persists non-session cookies using a JSON formatted file
*/
class FileCookieJar extends CookieJar
{
/** @var string filename */
private $filename;
/** @var bool Control whether to persist session cookies or not. */
private $storeSessionCookies;
/**
* Create a new FileCookieJar object
*
* @param string $cookieFile File to store the cookie data
* @param bool $storeSessionCookies Set to true to store session cookies
* in the cookie jar.
*
* @throws \RuntimeException if the file cannot be found or created
*/
public function __construct($cookieFile, $storeSessionCookies = false)
{
$this->filename = $cookieFile;
$this->storeSessionCookies = $storeSessionCookies;
if (file_exists($cookieFile)) {
$this->load($cookieFile);
}
}
/**
* Saves the file when shutting down
*/
public function __destruct()
{
$this->save($this->filename);
}
/**
* Saves the cookies to a file.
*
* @param string $filename File to save
* @throws \RuntimeException if the file cannot be found or created
*/
public function save($filename)
{
$json = [];
foreach ($this as $cookie) {
/** @var SetCookie $cookie */
if (CookieJar::shouldPersist($cookie, $this->storeSessionCookies)) {
$json[] = $cookie->toArray();
}
}
$jsonStr = \GuzzleHttp\json_encode($json);
if (false === file_put_contents($filename, $jsonStr)) {
throw new \RuntimeException("Unable to save file {$filename}");
}
}
/**
* Load cookies from a JSON formatted file.
*
* Old cookies are kept unless overwritten by newly loaded ones.
*
* @param string $filename Cookie file to load.
* @throws \RuntimeException if the file cannot be loaded.
*/
public function load($filename)
{
$json = file_get_contents($filename);
if (false === $json) {
throw new \RuntimeException("Unable to load file {$filename}");
} elseif ($json === '') {
return;
}
$data = \GuzzleHttp\json_decode($json, true);
if (is_array($data)) {
foreach (json_decode($json, true) as $cookie) {
$this->setCookie(new SetCookie($cookie));
}
} elseif (strlen($data)) {
throw new \RuntimeException("Invalid cookie file: {$filename}");
}
}
}
<?php
namespace GuzzleHttp\Cookie;
/**
* Persists cookies in the client session
*/
class SessionCookieJar extends CookieJar
{
/** @var string session key */
private $sessionKey;
/** @var bool Control whether to persist session cookies or not. */
private $storeSessionCookies;
/**
* Create a new SessionCookieJar object
*
* @param string $sessionKey Session key name to store the cookie
* data in session
* @param bool $storeSessionCookies Set to true to store session cookies
* in the cookie jar.
*/
public function __construct($sessionKey, $storeSessionCookies = false)
{
$this->sessionKey = $sessionKey;
$this->storeSessionCookies = $storeSessionCookies;
$this->load();
}
/**
* Saves cookies to session when shutting down
*/
public function __destruct()
{
$this->save();
}
/**
* Save cookies to the client session
*/
public function save()
{
$json = [];
foreach ($this as $cookie) {
/** @var SetCookie $cookie */
if (CookieJar::shouldPersist($cookie, $this->storeSessionCookies)) {
$json[] = $cookie->toArray();
}
}
$_SESSION[$this->sessionKey] = json_encode($json);
}
/**
* Load the contents of the client session into the data array
*/
protected function load()
{
if (!isset($_SESSION[$this->sessionKey])) {
return;
}
$data = json_decode($_SESSION[$this->sessionKey], true);
if (is_array($data)) {
foreach ($data as $cookie) {
$this->setCookie(new SetCookie($cookie));
}
} elseif (strlen($data)) {
throw new \RuntimeException("Invalid cookie data");
}
}
}
<?php
namespace GuzzleHttp\Exception;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
/**
* Exception when an HTTP error occurs (4xx or 5xx error)
*/
class BadResponseException extends RequestException
{
public function __construct(
$message,
RequestInterface $request,
ResponseInterface $response = null,
\Exception $previous = null,
array $handlerContext = []
) {
if (null === $response) {
@trigger_error(
'Instantiating the ' . __CLASS__ . ' class without a Response is deprecated since version 6.3 and will be removed in 7.0.',
E_USER_DEPRECATED
);
}
parent::__construct($message, $request, $response, $previous, $handlerContext);
}
}
<?php
namespace GuzzleHttp\Exception;
/**
* Exception when a client error is encountered (4xx codes)
*/
class ClientException extends BadResponseException {}
<?php
namespace GuzzleHttp\Exception;
use Psr\Http\Message\RequestInterface;
/**
* Exception thrown when a connection cannot be established.
*
* Note that no response is present for a ConnectException
*/
class ConnectException extends RequestException
{
public function __construct(
$message,
RequestInterface $request,
\Exception $previous = null,
array $handlerContext = []
) {
parent::__construct($message, $request, null, $previous, $handlerContext);
}
/**
* @return null
*/
public function getResponse()
{
return null;
}
/**
* @return bool
*/
public function hasResponse()
{
return false;
}
}
<?php
namespace GuzzleHttp\Exception;
/**
* @method string getMessage()
* @method \Throwable|null getPrevious()
* @method mixed getCode()
* @method string getFile()
* @method int getLine()
* @method array getTrace()
* @method string getTraceAsString()
*/
interface GuzzleException {}
<?php
namespace GuzzleHttp\Exception;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use GuzzleHttp\Promise\PromiseInterface;
use Psr\Http\Message\UriInterface;
/**
* HTTP Request exception
*/
class RequestException extends TransferException
{
/** @var RequestInterface */
private $request;
/** @var ResponseInterface */
private $response;
/** @var array */
private $handlerContext;
public function __construct(
$message,
RequestInterface $request,
ResponseInterface $response = null,
\Exception $previous = null,
array $handlerContext = []
) {
// Set the code of the exception if the response is set and not future.
$code = $response && !($response instanceof PromiseInterface)
? $response->getStatusCode()
: 0;
parent::__construct($message, $code, $previous);
$this->request = $request;
$this->response = $response;
$this->handlerContext = $handlerContext;
}
/**
* Wrap non-RequestExceptions with a RequestException
*
* @param RequestInterface $request
* @param \Exception $e
*
* @return RequestException
*/
public static function wrapException(RequestInterface $request, \Exception $e)
{
return $e instanceof RequestException
? $e
: new RequestException($e->getMessage(), $request, null, $e);
}
/**
* Factory method to create a new exception with a normalized error message
*
* @param RequestInterface $request Request
* @param ResponseInterface $response Response received
* @param \Exception $previous Previous exception
* @param array $ctx Optional handler context.
*
* @return self
*/
public static function create(
RequestInterface $request,
ResponseInterface $response = null,
\Exception $previous = null,
array $ctx = []
) {
if (!$response) {
return new self(
'Error completing request',
$request,
null,
$previous,
$ctx
);
}
$level = (int) floor($response->getStatusCode() / 100);
if ($level === 4) {
$label = 'Client error';
$className = ClientException::class;
} elseif ($level === 5) {
$label = 'Server error';
$className = ServerException::class;
} else {
$label = 'Unsuccessful request';
$className = __CLASS__;
}
$uri = $request->getUri();
$uri = static::obfuscateUri($uri);
// Client Error: `GET /` resulted in a `404 Not Found` response:
// <html> ... (truncated)
$message = sprintf(
'%s: `%s %s` resulted in a `%s %s` response',
$label,
$request->getMethod(),
$uri,
$response->getStatusCode(),
$response->getReasonPhrase()
);
$summary = static::getResponseBodySummary($response);
if ($summary !== null) {
$message .= ":\n{$summary}\n";
}
return new $className($message, $request, $response, $previous, $ctx);
}
/**
* Get a short summary of the response
*
* Will return `null` if the response is not printable.
*
* @param ResponseInterface $response
*
* @return string|null
*/
public static function getResponseBodySummary(ResponseInterface $response)
{
$body = $response->getBody();
if (!$body->isSeekable()) {
return null;
}
$size = $body->getSize();
if ($size === 0) {
return null;
}
$summary = $body->read(120);
$body->rewind();
if ($size > 120) {
$summary .= ' (truncated...)';
}
// Matches any printable character, including unicode characters:
// letters, marks, numbers, punctuation, spacing, and separators.
if (preg_match('/[^\pL\pM\pN\pP\pS\pZ\n\r\t]/', $summary)) {
return null;
}
return $summary;
}
/**
* Obfuscates URI if there is an username and a password present
*
* @param UriInterface $uri
*
* @return UriInterface
*/
private static function obfuscateUri($uri)
{
$userInfo = $uri->getUserInfo();
if (false !== ($pos = strpos($userInfo, ':'))) {
return $uri->withUserInfo(substr($userInfo, 0, $pos), '***');
}
return $uri;
}
/**
* Get the request that caused the exception
*
* @return RequestInterface
*/
public function getRequest()
{
return $this->request;
}
/**
* Get the associated response
*
* @return ResponseInterface|null
*/
public function getResponse()
{
return $this->response;
}
/**
* Check if a response was received
*
* @return bool
*/
public function hasResponse()
{
return $this->response !== null;
}
/**
* Get contextual information about the error from the underlying handler.
*
* The contents of this array will vary depending on which handler you are
* using. It may also be just an empty array. Relying on this data will
* couple you to a specific handler, but can give more debug information
* when needed.
*
* @return array
*/
public function getHandlerContext()
{
return $this->handlerContext;
}
}
<?php
namespace GuzzleHttp\Exception;
use Psr\Http\Message\StreamInterface;
/**
* Exception thrown when a seek fails on a stream.
*/
class SeekException extends \RuntimeException implements GuzzleException
{
private $stream;
public function __construct(StreamInterface $stream, $pos = 0, $msg = '')
{
$this->stream = $stream;
$msg = $msg ?: 'Could not seek the stream to position ' . $pos;
parent::__construct($msg);
}
/**
* @return StreamInterface
*/
public function getStream()
{
return $this->stream;
}
}
<?php
namespace GuzzleHttp\Exception;
/**
* Exception when a server error is encountered (5xx codes)
*/
class ServerException extends BadResponseException {}
<?php
namespace GuzzleHttp\Exception;
class TooManyRedirectsException extends RequestException {}
<?php
namespace GuzzleHttp\Exception;
class TransferException extends \RuntimeException implements GuzzleException {}
<?php
namespace GuzzleHttp\Handler;
use Psr\Http\Message\RequestInterface;
interface CurlFactoryInterface
{
/**
* Creates a cURL handle resource.
*
* @param RequestInterface $request Request
* @param array $options Transfer options
*
* @return EasyHandle
* @throws \RuntimeException when an option cannot be applied
*/
public function create(RequestInterface $request, array $options);
/**
* Release an easy handle, allowing it to be reused or closed.
*
* This function must call unset on the easy handle's "handle" property.
*
* @param EasyHandle $easy
*/
public function release(EasyHandle $easy);
}
<?php
namespace GuzzleHttp\Handler;
use GuzzleHttp\Psr7;
use Psr\Http\Message\RequestInterface;
/**
* HTTP handler that uses cURL easy handles as a transport layer.
*
* When using the CurlHandler, custom curl options can be specified as an
* associative array of curl option constants mapping to values in the
* **curl** key of the "client" key of the request.
*/
class CurlHandler
{
/** @var CurlFactoryInterface */
private $factory;
/**
* Accepts an associative array of options:
*
* - factory: Optional curl factory used to create cURL handles.
*
* @param array $options Array of options to use with the handler
*/
public function __construct(array $options = [])
{
$this->factory = isset($options['handle_factory'])
? $options['handle_factory']
: new CurlFactory(3);
}
public function __invoke(RequestInterface $request, array $options)
{
if (isset($options['delay'])) {
usleep($options['delay'] * 1000);
}
$easy = $this->factory->create($request, $options);
curl_exec($easy->handle);
$easy->errno = curl_errno($easy->handle);
return CurlFactory::finish($this, $easy, $this->factory);
}
}
<?php
namespace GuzzleHttp\Handler;
use GuzzleHttp\Promise as P;
use GuzzleHttp\Promise\Promise;
use GuzzleHttp\Psr7;
use Psr\Http\Message\RequestInterface;
/**
* Returns an asynchronous response using curl_multi_* functions.
*
* When using the CurlMultiHandler, custom curl options can be specified as an
* associative array of curl option constants mapping to values in the
* **curl** key of the provided request options.
*
* @property resource $_mh Internal use only. Lazy loaded multi-handle.
*/
class CurlMultiHandler
{
/** @var CurlFactoryInterface */
private $factory;
private $selectTimeout;
private $active;
private $handles = [];
private $delays = [];
/**
* This handler accepts the following options:
*
* - handle_factory: An optional factory used to create curl handles
* - select_timeout: Optional timeout (in seconds) to block before timing
* out while selecting curl handles. Defaults to 1 second.
*
* @param array $options
*/
public function __construct(array $options = [])
{
$this->factory = isset($options['handle_factory'])
? $options['handle_factory'] : new CurlFactory(50);
$this->selectTimeout = isset($options['select_timeout'])
? $options['select_timeout'] : 1;
}
public function __get($name)
{
if ($name === '_mh') {
return $this->_mh = curl_multi_init();
}
throw new \BadMethodCallException();
}
public function __destruct()
{
if (isset($this->_mh)) {
curl_multi_close($this->_mh);
unset($this->_mh);
}
}
public function __invoke(RequestInterface $request, array $options)
{
$easy = $this->factory->create($request, $options);
$id = (int) $easy->handle;
$promise = new Promise(
[$this, 'execute'],
function () use ($id) {
return $this->cancel($id);
}
);
$this->addRequest(['easy' => $easy, 'deferred' => $promise]);
return $promise;
}
/**
* Ticks the curl event loop.
*/
public function tick()
{
// Add any delayed handles if needed.
if ($this->delays) {
$currentTime = microtime(true);
foreach ($this->delays as $id => $delay) {
if ($currentTime >= $delay) {
unset($this->delays[$id]);
curl_multi_add_handle(
$this->_mh,
$this->handles[$id]['easy']->handle
);
}
}
}
// Step through the task queue which may add additional requests.
P\queue()->run();
if ($this->active &&
curl_multi_select($this->_mh, $this->selectTimeout) === -1
) {
// Perform a usleep if a select returns -1.
// See: https://bugs.php.net/bug.php?id=61141
usleep(250);
}
while (curl_multi_exec($this->_mh, $this->active) === CURLM_CALL_MULTI_PERFORM);
$this->processMessages();
}
/**
* Runs until all outstanding connections have completed.
*/
public function execute()
{
$queue = P\queue();
while ($this->handles || !$queue->isEmpty()) {
// If there are no transfers, then sleep for the next delay
if (!$this->active && $this->delays) {
usleep($this->timeToNext());
}
$this->tick();
}
}
private function addRequest(array $entry)
{
$easy = $entry['easy'];
$id = (int) $easy->handle;
$this->handles[$id] = $entry;
if (empty($easy->options['delay'])) {
curl_multi_add_handle($this->_mh, $easy->handle);
} else {
$this->delays[$id] = microtime(true) + ($easy->options['delay'] / 1000);
}
}
/**
* Cancels a handle from sending and removes references to it.
*
* @param int $id Handle ID to cancel and remove.
*
* @return bool True on success, false on failure.
*/
private function cancel($id)
{
// Cannot cancel if it has been processed.
if (!isset($this->handles[$id])) {
return false;
}
$handle = $this->handles[$id]['easy']->handle;
unset($this->delays[$id], $this->handles[$id]);
curl_multi_remove_handle($this->_mh, $handle);
curl_close($handle);
return true;
}
private function processMessages()
{
while ($done = curl_multi_info_read($this->_mh)) {
$id = (int) $done['handle'];
curl_multi_remove_handle($this->_mh, $done['handle']);
if (!isset($this->handles[$id])) {
// Probably was cancelled.
continue;
}
$entry = $this->handles[$id];
unset($this->handles[$id], $this->delays[$id]);
$entry['easy']->errno = $done['result'];
$entry['deferred']->resolve(
CurlFactory::finish(
$this,
$entry['easy'],
$this->factory
)
);
}
}
private function timeToNext()
{
$currentTime = microtime(true);
$nextTime = PHP_INT_MAX;
foreach ($this->delays as $time) {
if ($time < $nextTime) {
$nextTime = $time;
}
}
return max(0, $nextTime - $currentTime) * 1000000;
}
}
<?php
namespace GuzzleHttp\Handler;
use GuzzleHttp\Psr7\Response;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamInterface;
/**
* Represents a cURL easy handle and the data it populates.
*
* @internal
*/
final class EasyHandle
{
/** @var resource cURL resource */
public $handle;
/** @var StreamInterface Where data is being written */
public $sink;
/** @var array Received HTTP headers so far */
public $headers = [];
/** @var ResponseInterface Received response (if any) */
public $response;
/** @var RequestInterface Request being sent */
public $request;
/** @var array Request options */
public $options = [];
/** @var int cURL error number (if any) */
public $errno = 0;
/** @var \Exception Exception during on_headers (if any) */
public $onHeadersException;
/**
* Attach a response to the easy handle based on the received headers.
*
* @throws \RuntimeException if no headers have been received.
*/
public function createResponse()
{
if (empty($this->headers)) {
throw new \RuntimeException('No headers have been received');
}
// HTTP-version SP status-code SP reason-phrase
$startLine = explode(' ', array_shift($this->headers), 3);
$headers = \GuzzleHttp\headers_from_lines($this->headers);
$normalizedKeys = \GuzzleHttp\normalize_header_keys($headers);
if (!empty($this->options['decode_content'])
&& isset($normalizedKeys['content-encoding'])
) {
$headers['x-encoded-content-encoding']
= $headers[$normalizedKeys['content-encoding']];
unset($headers[$normalizedKeys['content-encoding']]);
if (isset($normalizedKeys['content-length'])) {
$headers['x-encoded-content-length']
= $headers[$normalizedKeys['content-length']];
$bodyLength = (int) $this->sink->getSize();
if ($bodyLength) {
$headers[$normalizedKeys['content-length']] = $bodyLength;
} else {
unset($headers[$normalizedKeys['content-length']]);
}
}
}
// Attach a response to the easy handle with the parsed headers.
$this->response = new Response(
$startLine[1],
$headers,
$this->sink,
substr($startLine[0], 5),
isset($startLine[2]) ? (string) $startLine[2] : null
);
}
public function __get($name)
{
$msg = $name === 'handle'
? 'The EasyHandle has been released'
: 'Invalid property: ' . $name;
throw new \BadMethodCallException($msg);
}
}
<?php
namespace GuzzleHttp\Handler;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Promise\PromiseInterface;
use GuzzleHttp\Promise\RejectedPromise;
use GuzzleHttp\TransferStats;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
/**
* Handler that returns responses or throw exceptions from a queue.
*/
class MockHandler implements \Countable
{
private $queue = [];
private $lastRequest;
private $lastOptions;
private $onFulfilled;
private $onRejected;
/**
* Creates a new MockHandler that uses the default handler stack list of
* middlewares.
*
* @param array $queue Array of responses, callables, or exceptions.
* @param callable $onFulfilled Callback to invoke when the return value is fulfilled.
* @param callable $onRejected Callback to invoke when the return value is rejected.
*
* @return HandlerStack
*/
public static function createWithMiddleware(
array $queue = null,
callable $onFulfilled = null,
callable $onRejected = null
) {
return HandlerStack::create(new self($queue, $onFulfilled, $onRejected));
}
/**
* The passed in value must be an array of
* {@see Psr7\Http\Message\ResponseInterface} objects, Exceptions,
* callables, or Promises.
*
* @param array $queue
* @param callable $onFulfilled Callback to invoke when the return value is fulfilled.
* @param callable $onRejected Callback to invoke when the return value is rejected.
*/
public function __construct(
array $queue = null,
callable $onFulfilled = null,
callable $onRejected = null
) {
$this->onFulfilled = $onFulfilled;
$this->onRejected = $onRejected;
if ($queue) {
call_user_func_array([$this, 'append'], $queue);
}
}
public function __invoke(RequestInterface $request, array $options)
{
if (!$this->queue) {
throw new \OutOfBoundsException('Mock queue is empty');
}
if (isset($options['delay'])) {
usleep($options['delay'] * 1000);
}
$this->lastRequest = $request;
$this->lastOptions = $options;
$response = array_shift($this->queue);
if (isset($options['on_headers'])) {
if (!is_callable($options['on_headers'])) {
throw new \InvalidArgumentException('on_headers must be callable');
}
try {
$options['on_headers']($response);
} catch (\Exception $e) {
$msg = 'An error was encountered during the on_headers event';
$response = new RequestException($msg, $request, $response, $e);
}
}
if (is_callable($response)) {
$response = call_user_func($response, $request, $options);
}
$response = $response instanceof \Exception
? \GuzzleHttp\Promise\rejection_for($response)
: \GuzzleHttp\Promise\promise_for($response);
return $response->then(
function ($value) use ($request, $options) {
$this->invokeStats($request, $options, $value);
if ($this->onFulfilled) {
call_user_func($this->onFulfilled, $value);
}
if (isset($options['sink'])) {
$contents = (string) $value->getBody();
$sink = $options['sink'];
if (is_resource($sink)) {
fwrite($sink, $contents);
} elseif (is_string($sink)) {
file_put_contents($sink, $contents);
} elseif ($sink instanceof \Psr\Http\Message\StreamInterface) {
$sink->write($contents);
}
}
return $value;
},
function ($reason) use ($request, $options) {
$this->invokeStats($request, $options, null, $reason);
if ($this->onRejected) {
call_user_func($this->onRejected, $reason);
}
return \GuzzleHttp\Promise\rejection_for($reason);
}
);
}
/**
* Adds one or more variadic requests, exceptions, callables, or promises
* to the queue.
*/
public function append()
{
foreach (func_get_args() as $value) {
if ($value instanceof ResponseInterface
|| $value instanceof \Exception
|| $value instanceof PromiseInterface
|| is_callable($value)
) {
$this->queue[] = $value;
} else {
throw new \InvalidArgumentException('Expected a response or '
. 'exception. Found ' . \GuzzleHttp\describe_type($value));
}
}
}
/**
* Get the last received request.
*
* @return RequestInterface
*/
public function getLastRequest()
{
return $this->lastRequest;
}
/**
* Get the last received request options.
*
* @return array
*/
public function getLastOptions()
{
return $this->lastOptions;
}
/**
* Returns the number of remaining items in the queue.
*
* @return int
*/
public function count()
{
return count($this->queue);
}
private function invokeStats(
RequestInterface $request,
array $options,
ResponseInterface $response = null,
$reason = null
) {
if (isset($options['on_stats'])) {
$stats = new TransferStats($request, $response, 0, $reason);
call_user_func($options['on_stats'], $stats);
}
}
}
<?php
namespace GuzzleHttp\Handler;
use GuzzleHttp\RequestOptions;
use Psr\Http\Message\RequestInterface;
/**
* Provides basic proxies for handlers.
*/
class Proxy
{
/**
* Sends synchronous requests to a specific handler while sending all other
* requests to another handler.
*
* @param callable $default Handler used for normal responses
* @param callable $sync Handler used for synchronous responses.
*
* @return callable Returns the composed handler.
*/
public static function wrapSync(
callable $default,
callable $sync
) {
return function (RequestInterface $request, array $options) use ($default, $sync) {
return empty($options[RequestOptions::SYNCHRONOUS])
? $default($request, $options)
: $sync($request, $options);
};
}
/**
* Sends streaming requests to a streaming compatible handler while sending
* all other requests to a default handler.
*
* This, for example, could be useful for taking advantage of the
* performance benefits of curl while still supporting true streaming
* through the StreamHandler.
*
* @param callable $default Handler used for non-streaming responses
* @param callable $streaming Handler used for streaming responses
*
* @return callable Returns the composed handler.
*/
public static function wrapStreaming(
callable $default,
callable $streaming
) {
return function (RequestInterface $request, array $options) use ($default, $streaming) {
return empty($options['stream'])
? $default($request, $options)
: $streaming($request, $options);
};
}
}
<?php
namespace GuzzleHttp;
use Psr\Http\Message\RequestInterface;
/**
* Creates a composed Guzzle handler function by stacking middlewares on top of
* an HTTP handler function.
*/
class HandlerStack
{
/** @var callable */
private $handler;
/** @var array */
private $stack = [];
/** @var callable|null */
private $cached;
/**
* Creates a default handler stack that can be used by clients.
*
* The returned handler will wrap the provided handler or use the most
* appropriate default handler for your system. The returned HandlerStack has
* support for cookies, redirects, HTTP error exceptions, and preparing a body
* before sending.
*
* The returned handler stack can be passed to a client in the "handler"
* option.
*
* @param callable $handler HTTP handler function to use with the stack. If no
* handler is provided, the best handler for your
* system will be utilized.
*
* @return HandlerStack
*/
public static function create(callable $handler = null)
{
$stack = new self($handler ?: choose_handler());
$stack->push(Middleware::httpErrors(), 'http_errors');
$stack->push(Middleware::redirect(), 'allow_redirects');
$stack->push(Middleware::cookies(), 'cookies');
$stack->push(Middleware::prepareBody(), 'prepare_body');
return $stack;
}
/**
* @param callable $handler Underlying HTTP handler.
*/
public function __construct(callable $handler = null)
{
$this->handler = $handler;
}
/**
* Invokes the handler stack as a composed handler
*
* @param RequestInterface $request
* @param array $options
*/
public function __invoke(RequestInterface $request, array $options)
{
$handler = $this->resolve();
return $handler($request, $options);
}
/**
* Dumps a string representation of the stack.
*
* @return string
*/
public function __toString()
{
$depth = 0;
$stack = [];
if ($this->handler) {
$stack[] = "0) Handler: " . $this->debugCallable($this->handler);
}
$result = '';
foreach (array_reverse($this->stack) as $tuple) {
$depth++;
$str = "{$depth}) Name: '{$tuple[1]}', ";
$str .= "Function: " . $this->debugCallable($tuple[0]);
$result = "> {$str}\n{$result}";
$stack[] = $str;
}
foreach (array_keys($stack) as $k) {
$result .= "< {$stack[$k]}\n";
}
return $result;
}
/**
* Set the HTTP handler that actually returns a promise.
*
* @param callable $handler Accepts a request and array of options and
* returns a Promise.
*/
public function setHandler(callable $handler)
{
$this->handler = $handler;
$this->cached = null;
}
/**
* Returns true if the builder has a handler.
*
* @return bool
*/
public function hasHandler()
{
return (bool) $this->handler;
}
/**
* Unshift a middleware to the bottom of the stack.
*
* @param callable $middleware Middleware function
* @param string $name Name to register for this middleware.
*/
public function unshift(callable $middleware, $name = null)
{
array_unshift($this->stack, [$middleware, $name]);
$this->cached = null;
}
/**
* Push a middleware to the top of the stack.
*
* @param callable $middleware Middleware function
* @param string $name Name to register for this middleware.
*/
public function push(callable $middleware, $name = '')
{
$this->stack[] = [$middleware, $name];
$this->cached = null;
}
/**
* Add a middleware before another middleware by name.
*
* @param string $findName Middleware to find
* @param callable $middleware Middleware function
* @param string $withName Name to register for this middleware.
*/
public function before($findName, callable $middleware, $withName = '')
{
$this->splice($findName, $withName, $middleware, true);
}
/**
* Add a middleware after another middleware by name.
*
* @param string $findName Middleware to find
* @param callable $middleware Middleware function
* @param string $withName Name to register for this middleware.
*/
public function after($findName, callable $middleware, $withName = '')
{
$this->splice($findName, $withName, $middleware, false);
}
/**
* Remove a middleware by instance or name from the stack.
*
* @param callable|string $remove Middleware to remove by instance or name.
*/
public function remove($remove)
{
$this->cached = null;
$idx = is_callable($remove) ? 0 : 1;
$this->stack = array_values(array_filter(
$this->stack,
function ($tuple) use ($idx, $remove) {
return $tuple[$idx] !== $remove;
}
));
}
/**
* Compose the middleware and handler into a single callable function.
*
* @return callable
*/
public function resolve()
{
if (!$this->cached) {
if (!($prev = $this->handler)) {
throw new \LogicException('No handler has been specified');
}
foreach (array_reverse($this->stack) as $fn) {
$prev = $fn[0]($prev);
}
$this->cached = $prev;
}
return $this->cached;
}
/**
* @param $name
* @return int
*/
private function findByName($name)
{
foreach ($this->stack as $k => $v) {
if ($v[1] === $name) {
return $k;
}
}
throw new \InvalidArgumentException("Middleware not found: $name");
}
/**
* Splices a function into the middleware list at a specific position.
*
* @param $findName
* @param $withName
* @param callable $middleware
* @param $before
*/
private function splice($findName, $withName, callable $middleware, $before)
{
$this->cached = null;
$idx = $this->findByName($findName);
$tuple = [$middleware, $withName];
if ($before) {
if ($idx === 0) {
array_unshift($this->stack, $tuple);
} else {
$replacement = [$tuple, $this->stack[$idx]];
array_splice($this->stack, $idx, 1, $replacement);
}
} elseif ($idx === count($this->stack) - 1) {
$this->stack[] = $tuple;
} else {
$replacement = [$this->stack[$idx], $tuple];
array_splice($this->stack, $idx, 1, $replacement);
}
}
/**
* Provides a debug string for a given callable.
*
* @param array|callable $fn Function to write as a string.
*
* @return string
*/
private function debugCallable($fn)
{
if (is_string($fn)) {
return "callable({$fn})";
}
if (is_array($fn)) {
return is_string($fn[0])
? "callable({$fn[0]}::{$fn[1]})"
: "callable(['" . get_class($fn[0]) . "', '{$fn[1]}'])";
}
return 'callable(' . spl_object_hash($fn) . ')';
}
}
<?php
namespace GuzzleHttp;
use Psr\Http\Message\MessageInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
/**
* Formats log messages using variable substitutions for requests, responses,
* and other transactional data.
*
* The following variable substitutions are supported:
*
* - {request}: Full HTTP request message
* - {response}: Full HTTP response message
* - {ts}: ISO 8601 date in GMT
* - {date_iso_8601} ISO 8601 date in GMT
* - {date_common_log} Apache common log date using the configured timezone.
* - {host}: Host of the request
* - {method}: Method of the request
* - {uri}: URI of the request
* - {version}: Protocol version
* - {target}: Request target of the request (path + query + fragment)
* - {hostname}: Hostname of the machine that sent the request
* - {code}: Status code of the response (if available)
* - {phrase}: Reason phrase of the response (if available)
* - {error}: Any error messages (if available)
* - {req_header_*}: Replace `*` with the lowercased name of a request header to add to the message
* - {res_header_*}: Replace `*` with the lowercased name of a response header to add to the message
* - {req_headers}: Request headers
* - {res_headers}: Response headers
* - {req_body}: Request body
* - {res_body}: Response body
*/
class MessageFormatter
{
/**
* Apache Common Log Format.
* @link http://httpd.apache.org/docs/2.4/logs.html#common
* @var string
*/
const CLF = "{hostname} {req_header_User-Agent} - [{date_common_log}] \"{method} {target} HTTP/{version}\" {code} {res_header_Content-Length}";
const DEBUG = ">>>>>>>>\n{request}\n<<<<<<<<\n{response}\n--------\n{error}";
const SHORT = '[{ts}] "{method} {target} HTTP/{version}" {code}';
/** @var string Template used to format log messages */
private $template;
/**
* @param string $template Log message template
*/
public function __construct($template = self::CLF)
{
$this->template = $template ?: self::CLF;
}
/**
* Returns a formatted message string.
*
* @param RequestInterface $request Request that was sent
* @param ResponseInterface $response Response that was received
* @param \Exception $error Exception that was received
*
* @return string
*/
public function format(
RequestInterface $request,
ResponseInterface $response = null,
\Exception $error = null
) {
$cache = [];
return preg_replace_callback(
'/{\s*([A-Za-z_\-\.0-9]+)\s*}/',
function (array $matches) use ($request, $response, $error, &$cache) {
if (isset($cache[$matches[1]])) {
return $cache[$matches[1]];
}
$result = '';
switch ($matches[1]) {
case 'request':
$result = Psr7\str($request);
break;
case 'response':
$result = $response ? Psr7\str($response) : '';
break;
case 'req_headers':
$result = trim($request->getMethod()
. ' ' . $request->getRequestTarget())
. ' HTTP/' . $request->getProtocolVersion() . "\r\n"
. $this->headers($request);
break;
case 'res_headers':
$result = $response ?
sprintf(
'HTTP/%s %d %s',
$response->getProtocolVersion(),
$response->getStatusCode(),
$response->getReasonPhrase()
) . "\r\n" . $this->headers($response)
: 'NULL';
break;
case 'req_body':
$result = $request->getBody();
break;
case 'res_body':
$result = $response ? $response->getBody() : 'NULL';
break;
case 'ts':
case 'date_iso_8601':
$result = gmdate('c');
break;
case 'date_common_log':
$result = date('d/M/Y:H:i:s O');
break;
case 'method':
$result = $request->getMethod();
break;
case 'version':
$result = $request->getProtocolVersion();
break;
case 'uri':
case 'url':
$result = $request->getUri();
break;
case 'target':
$result = $request->getRequestTarget();
break;
case 'req_version':
$result = $request->getProtocolVersion();
break;
case 'res_version':
$result = $response
? $response->getProtocolVersion()
: 'NULL';
break;
case 'host':
$result = $request->getHeaderLine('Host');
break;
case 'hostname':
$result = gethostname();
break;
case 'code':
$result = $response ? $response->getStatusCode() : 'NULL';
break;
case 'phrase':
$result = $response ? $response->getReasonPhrase() : 'NULL';
break;
case 'error':
$result = $error ? $error->getMessage() : 'NULL';
break;
default:
// handle prefixed dynamic headers
if (strpos($matches[1], 'req_header_') === 0) {
$result = $request->getHeaderLine(substr($matches[1], 11));
} elseif (strpos($matches[1], 'res_header_') === 0) {
$result = $response
? $response->getHeaderLine(substr($matches[1], 11))
: 'NULL';
}
}
$cache[$matches[1]] = $result;
return $result;
},
$this->template
);
}
private function headers(MessageInterface $message)
{
$result = '';
foreach ($message->getHeaders() as $name => $values) {
$result .= $name . ': ' . implode(', ', $values) . "\r\n";
}
return trim($result);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment