first commit
This commit is contained in:
86
lib/Utils/DateUtils.php
Normal file
86
lib/Utils/DateUtils.php
Normal file
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
namespace Yeepay\Yop\Sdk\Utils;
|
||||
|
||||
/**
|
||||
* Utilities for parsing and formatting dates.
|
||||
* <p>
|
||||
* Note that this class doesn't use static methods because of the
|
||||
* synchronization issues with SimpleDateFormat. This lets synchronization be
|
||||
* done on a per-object level, instead of on a per-class level.
|
||||
*/
|
||||
class DateUtils
|
||||
{
|
||||
|
||||
/**
|
||||
* Alternate ISO 8601 format without fractional seconds
|
||||
*/
|
||||
const ALTERNATE_ISO8601_DATE_FORMAT = "Y-m-d\TH:i:s\Z";
|
||||
|
||||
/**
|
||||
* @var \DateTimeZone The UTC timezone object.
|
||||
*/
|
||||
public static $UTC_TIMEZONE;
|
||||
|
||||
/**
|
||||
* Initialize $UTC_TIMEZONE
|
||||
*/
|
||||
public static function __init()
|
||||
{
|
||||
DateUtils::$UTC_TIMEZONE = new \DateTimeZone("UTC");
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the specified date string as an ISO 8601 date and returns the Date
|
||||
* object.
|
||||
* @param $dateString string The date string to parse.
|
||||
* @return \DateTime The parsed Date object.
|
||||
* @throws \Exception If the date string could not be parsed.
|
||||
*/
|
||||
public static function parseAlternateIso8601Date($dateString)
|
||||
{
|
||||
return \DateTime::createFromFormat(
|
||||
DateUtils::ALTERNATE_ISO8601_DATE_FORMAT,
|
||||
$dateString,
|
||||
DateUtils::$UTC_TIMEZONE
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the specified date as an ISO 8601 string.
|
||||
* @param $datetime \DateTime The date to format.
|
||||
* @return string The ISO 8601 string representing the specified date.
|
||||
*/
|
||||
public static function formatAlternateIso8601Date($datetime)
|
||||
{
|
||||
return $datetime->format(DateUtils::ALTERNATE_ISO8601_DATE_FORMAT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the specified date string as an RFC 822 date and returns the Date object.
|
||||
* @param $dateString string The date string to parse.
|
||||
* @return \DateTime The parsed Date object.
|
||||
* @throws \Exception If the date string could not be parsed.
|
||||
*/
|
||||
public static function parseRfc822Date($dateString)
|
||||
{
|
||||
return \DateTime::createFromFormat(
|
||||
'D, d M y H:i:s O',
|
||||
$dateString,
|
||||
DateUtils::$UTC_TIMEZONE
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the specified date as an RFC 822 string.
|
||||
* @param $datetime \DateTime The date to format.
|
||||
* @return string The RFC 822 string representing the specified date.
|
||||
*/
|
||||
public static function formatRfc822Date($datetime)
|
||||
{
|
||||
return $datetime->format('D, d M y H:i:s O');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DateUtils::__init();
|
||||
188
lib/Utils/Http/HttpUtils.php
Normal file
188
lib/Utils/Http/HttpUtils.php
Normal file
@@ -0,0 +1,188 @@
|
||||
<?php
|
||||
|
||||
namespace Yeepay\Yop\Sdk\Utils\Http;
|
||||
|
||||
use GuzzleHttp\Psr7\Uri;
|
||||
use Yeepay\Yop\Sdk\Http\Headers;
|
||||
use Yeepay\Yop\Sdk\Http\HttpMethod;
|
||||
use Yeepay\Yop\Sdk\Internal\Request;
|
||||
|
||||
class HttpUtils
|
||||
{
|
||||
|
||||
private static $defaultPorts;
|
||||
|
||||
private static $PERCENT_ENCODED_STRINGS;
|
||||
|
||||
public static function __init()
|
||||
{
|
||||
self::$defaultPorts = ["http" => 80, "https" => 443];
|
||||
HttpUtils::$PERCENT_ENCODED_STRINGS = [];
|
||||
for ($i = 0; $i < 256; ++$i) {
|
||||
HttpUtils::$PERCENT_ENCODED_STRINGS[$i] = sprintf("%%%02X", $i);
|
||||
}
|
||||
foreach (range('a', 'z') as $ch) {
|
||||
HttpUtils::$PERCENT_ENCODED_STRINGS[ord($ch)] = $ch;
|
||||
}
|
||||
|
||||
foreach (range('A', 'Z') as $ch) {
|
||||
HttpUtils::$PERCENT_ENCODED_STRINGS[ord($ch)] = $ch;
|
||||
}
|
||||
|
||||
foreach (range('0', '9') as $ch) {
|
||||
HttpUtils::$PERCENT_ENCODED_STRINGS[ord($ch)] = $ch;
|
||||
}
|
||||
HttpUtils::$PERCENT_ENCODED_STRINGS[ord('-')] = '-';
|
||||
HttpUtils::$PERCENT_ENCODED_STRINGS[ord('.')] = '.';
|
||||
HttpUtils::$PERCENT_ENCODED_STRINGS[ord('_')] = '_';
|
||||
HttpUtils::$PERCENT_ENCODED_STRINGS[ord('~')] = '~';
|
||||
}
|
||||
|
||||
public static function generateHostHeader(Uri $uri)
|
||||
{
|
||||
$host = $uri->getHost();
|
||||
if (self::isUsingNonDefaultPort($uri)) {
|
||||
$host .= ':'.$uri->getPort();
|
||||
}
|
||||
|
||||
return $host;
|
||||
}
|
||||
|
||||
public static function isUsingNonDefaultPort(Uri $uri)
|
||||
{
|
||||
$schema = strtolower($uri->getScheme());
|
||||
$port = $uri->getPort();
|
||||
if (empty($port) && $port < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $port != self::$defaultPorts[$schema];
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize a string for use in url path. The algorithm is:
|
||||
* <p>
|
||||
* <ol>
|
||||
* <li>Normalize the string</li>
|
||||
* <li>replace all "%2F" with "/"</li>
|
||||
* <li>replace all "//" with "/%2F"</li>
|
||||
* </ol>
|
||||
* <p>
|
||||
* Bos object key can contain arbitrary characters, which may result double
|
||||
* slash in the url path. Apache Http client will replace "//" in the path
|
||||
* with a single '/', which makes the object key incorrect. Thus we replace
|
||||
* "//" with "/%2F" here.
|
||||
* @param $path string the path string to normalize.
|
||||
* @return string the normalized path string.
|
||||
* @see #normalize(string)
|
||||
*/
|
||||
public static function urlEncodeExceptSlash($path)
|
||||
{
|
||||
return str_replace("%2F", "/", self::urlEncode($path));
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize a string for use in BCE web service APIs. The normalization
|
||||
* algorithm is:
|
||||
* <p>
|
||||
* <ol>
|
||||
* <li>Convert the string into a UTF-8 byte array.</li>
|
||||
* <li>Encode all octets into percent-encoding, except all URI unreserved
|
||||
* characters per the RFC 3986.</li>
|
||||
* </ol>
|
||||
* <p>
|
||||
* All letters used in the percent-encoding are in uppercase.
|
||||
* @param $value string the string to normalize.
|
||||
* @return string the normalized string.
|
||||
*/
|
||||
public static function urlEncode($value)
|
||||
{
|
||||
$result = '';
|
||||
for ($i = 0; $i < strlen($value); ++$i) {
|
||||
$result .= self::$PERCENT_ENCODED_STRINGS[ord($value[$i])];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $parameters array
|
||||
* @param $forSignature bool
|
||||
* @return string
|
||||
*/
|
||||
public static function getCanonicalQueryString(array $parameters, $forSignature)
|
||||
{
|
||||
if (count($parameters) == 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$parameterStrings = [];
|
||||
foreach ($parameters as $name => $values) {
|
||||
if ($forSignature
|
||||
&& strcasecmp(Headers::AUTHORIZATION, $name) == 0) {
|
||||
continue;
|
||||
}
|
||||
if (!isset($name)) {
|
||||
throw new \InvalidArgumentException(
|
||||
"parameter key should not be null"
|
||||
);
|
||||
}
|
||||
if (empty($values)) {
|
||||
if ($forSignature) {
|
||||
$parameterStrings[] = self::urlEncode($name).'=';
|
||||
} else {
|
||||
$parameterStrings[] = self::urlEncode($name);
|
||||
}
|
||||
} else {
|
||||
foreach ($values as $value) {
|
||||
$parameterStrings[] = self::urlEncode($name)
|
||||
.'='.self::urlEncode($value);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if ($forSignature) {
|
||||
sort($parameterStrings);
|
||||
}
|
||||
|
||||
return implode('&', $parameterStrings);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $parameters
|
||||
* @return array
|
||||
*/
|
||||
public static function encodedParameters(array $parameters)
|
||||
{
|
||||
if (empty($parameters)) {
|
||||
return [];
|
||||
}
|
||||
$encodedParameters = [];
|
||||
foreach ($parameters as $name => $values) {
|
||||
if (empty($values)) {
|
||||
$encodedParameters[$name] = '';
|
||||
} elseif (count($values) == 1) {
|
||||
$encodedParameters[$name] = self::urlEncode($values[0]);
|
||||
} else {
|
||||
$targetValues = [];
|
||||
foreach ($values as $value) {
|
||||
$targetValues[] = self::urlEncode($value);
|
||||
}
|
||||
$encodedParameters[$name] = $targetValues;
|
||||
}
|
||||
}
|
||||
|
||||
return $encodedParameters;
|
||||
}
|
||||
|
||||
public static function usePayloadForQueryParameters(Request $request)
|
||||
{
|
||||
$requestIsPOST = HttpMethod::POST == $request->getHttpMethod();
|
||||
$requestHasNoPayload = empty($request->getContent());
|
||||
|
||||
return $requestIsPOST && $requestHasNoPayload;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
HttpUtils::__init();
|
||||
16
lib/Utils/Http/Region.php
Normal file
16
lib/Utils/Http/Region.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Yeepay\Yop\Sdk\Utils\Http;
|
||||
|
||||
class Region
|
||||
{
|
||||
|
||||
const CN_N1 = '';
|
||||
|
||||
const CN_SJ = 'sj';
|
||||
|
||||
const CN_DJ = 'dj';
|
||||
|
||||
const CN_M6 = 'm6';
|
||||
|
||||
}
|
||||
265
lib/Utils/ObjectSerializer.php
Normal file
265
lib/Utils/ObjectSerializer.php
Normal file
@@ -0,0 +1,265 @@
|
||||
<?php
|
||||
|
||||
namespace Yeepay\Yop\Sdk\Utils;
|
||||
|
||||
class ObjectSerializer
|
||||
{
|
||||
|
||||
/**
|
||||
* Serialize data
|
||||
* @param mixed $data the data to serialize
|
||||
* @param string $type the SwaggerType of the data
|
||||
* @param string $format the format of the Swagger type of the data
|
||||
* @return string|object serialized form of $data
|
||||
*/
|
||||
public static function sanitizeForSerialization($data, $type = null, $format = null)
|
||||
{
|
||||
if (is_scalar($data) || null === $data) {
|
||||
return $data;
|
||||
} elseif ($data instanceof \DateTime) {
|
||||
return ($format === 'date') ? $data->format('Y-m-d') : $data->format('Y-m-d H:i:s');
|
||||
} elseif (is_array($data)) {
|
||||
foreach ($data as $property => $value) {
|
||||
$data[$property] = self::sanitizeForSerialization($value);
|
||||
}
|
||||
|
||||
return $data;
|
||||
} elseif (is_object($data)) {
|
||||
$values = [];
|
||||
$formats = $data::swaggerFormats();
|
||||
foreach ($data::swaggerTypes() as $property => $swaggerType) {
|
||||
$getter = $data::getters()[$property];
|
||||
$value = $data->$getter();
|
||||
if ($value !== null
|
||||
&& !in_array($swaggerType, [
|
||||
'DateTime', 'bool', 'boolean', 'byte', 'double', 'float', 'int', 'integer', 'mixed', 'number',
|
||||
'object', 'string', 'void',
|
||||
], true)
|
||||
&& method_exists($swaggerType, 'getAllowableEnumValues')
|
||||
&& !in_array($value, $swaggerType::getAllowableEnumValues())) {
|
||||
$imploded = implode("', '", $swaggerType::getAllowableEnumValues());
|
||||
throw new \InvalidArgumentException("Invalid value for enum '$swaggerType', must be one of: '$imploded'");
|
||||
}
|
||||
if ($value !== null) {
|
||||
$values[$data::attributeMap()[$property]] = self::sanitizeForSerialization($value, $swaggerType,
|
||||
$formats[$property]);
|
||||
}
|
||||
}
|
||||
|
||||
return (object) $values;
|
||||
} else {
|
||||
return (string) $data;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize filename by removing path.
|
||||
* e.g. ../../sun.gif becomes sun.gif
|
||||
* @param string $filename filename to be sanitized
|
||||
* @return string the sanitized filename
|
||||
*/
|
||||
public static function sanitizeFilename($filename)
|
||||
{
|
||||
if (preg_match("/.*[\/\\\\](.*)$/", $filename, $match)) {
|
||||
return $match[1];
|
||||
} else {
|
||||
return $filename;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Take value and turn it into a string suitable for inclusion in
|
||||
* the path, by url-encoding.
|
||||
* @param string $value a string which will be part of the path
|
||||
* @return string the serialized object
|
||||
*/
|
||||
public static function toPathValue($value)
|
||||
{
|
||||
return rawurlencode(self::toString($value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Take value and turn it into a string suitable for inclusion in
|
||||
* the query, by imploding comma-separated if it's an object.
|
||||
* If it's a string, pass through unchanged. It will be url-encoded
|
||||
* later.
|
||||
* @param string[]|string|\DateTime $object an object to be serialized to a string
|
||||
* @return string the serialized object
|
||||
*/
|
||||
public static function toQueryValue($object)
|
||||
{
|
||||
if (is_array($object)) {
|
||||
return implode(',', $object);
|
||||
} else {
|
||||
return self::toString($object);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Take value and turn it into a string suitable for inclusion in
|
||||
* the header. If it's a string, pass through unchanged
|
||||
* If it's a datetime object, format it in ISO8601
|
||||
* @param string $value a string which will be part of the header
|
||||
* @return string the header string
|
||||
*/
|
||||
public static function toHeaderValue($value)
|
||||
{
|
||||
return self::toString($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Take value and turn it into a string suitable for inclusion in
|
||||
* the http body (form parameter). If it's a string, pass through unchanged
|
||||
* If it's a datetime object, format it in ISO8601
|
||||
* @param string|\SplFileObject $value the value of the form parameter
|
||||
* @return string the form string
|
||||
*/
|
||||
public static function toFormValue($value)
|
||||
{
|
||||
if ($value instanceof \SplFileObject) {
|
||||
return $value->getRealPath();
|
||||
} else {
|
||||
return self::toString($value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Take value and turn it into a string suitable for inclusion in
|
||||
* the parameter. If it's a string, pass through unchanged
|
||||
* If it's a datetime object, format it in ISO8601
|
||||
* @param string|\DateTime $value the value of the parameter
|
||||
* @return string the header string
|
||||
*/
|
||||
public static function toString($value)
|
||||
{
|
||||
if ($value instanceof \DateTime) { // datetime in ISO8601 format
|
||||
return $value->format('Y-m-d H:i:s');
|
||||
} else {
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize an array to a string.
|
||||
* @param array $collection collection to serialize to a string
|
||||
* @param string $collectionFormat the format use for serialization (csv,
|
||||
* ssv, tsv, pipes, multi)
|
||||
* @param bool $allowCollectionFormatMulti allow collection format to be a multidimensional array
|
||||
* @return string
|
||||
*/
|
||||
public static function serializeCollection(
|
||||
array $collection,
|
||||
$collectionFormat,
|
||||
$allowCollectionFormatMulti = false
|
||||
) {
|
||||
if ($allowCollectionFormatMulti && ('multi' === $collectionFormat)) {
|
||||
// http_build_query() almost does the job for us. We just
|
||||
// need to fix the result of multidimensional arrays.
|
||||
return preg_replace('/%5B[0-9]+%5D=/', '=', http_build_query($collection, '', '&'));
|
||||
}
|
||||
switch ($collectionFormat) {
|
||||
case 'pipes':
|
||||
return implode('|', $collection);
|
||||
|
||||
case 'tsv':
|
||||
return implode("\t", $collection);
|
||||
|
||||
case 'ssv':
|
||||
return implode(' ', $collection);
|
||||
|
||||
case 'csv':
|
||||
// Deliberate fall through. CSV is default format.
|
||||
default:
|
||||
return implode(',', $collection);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserialize a JSON string into an object
|
||||
* @param mixed $data object or primitive to be deserialized
|
||||
* @param string $class class name is passed as a string
|
||||
* @param string[] $httpHeaders HTTP headers
|
||||
* @return object|array|null an single or an array of $class instances
|
||||
*/
|
||||
public static function deserialize($data, $class, $httpHeaders = null)
|
||||
{
|
||||
if (null === $data) {
|
||||
return null;
|
||||
} elseif (substr($class, 0, 4) === 'map[') { // for associative array e.g. map[string,int]
|
||||
$inner = substr($class, 4, -1);
|
||||
$deserialized = [];
|
||||
if (strrpos($inner, ",") !== false) {
|
||||
$subClass_array = explode(',', $inner, 2);
|
||||
$subClass = $subClass_array[1];
|
||||
foreach ($data as $key => $value) {
|
||||
$deserialized[$key] = self::deserialize($value, $subClass, null);
|
||||
}
|
||||
}
|
||||
|
||||
return $deserialized;
|
||||
} elseif (strcasecmp(substr($class, -2), '[]') === 0) {
|
||||
$subClass = substr($class, 0, -2);
|
||||
$values = [];
|
||||
foreach ($data as $key => $value) {
|
||||
$values[] = self::deserialize($value, $subClass, null);
|
||||
}
|
||||
|
||||
return $values;
|
||||
} elseif ($class === 'object') {
|
||||
settype($data, 'array');
|
||||
|
||||
return $data;
|
||||
} elseif ($class === '\DateTime') {
|
||||
// Some API's return an invalid, empty string as a
|
||||
// date-time property. DateTime::__construct() will return
|
||||
// the current time for empty input which is probably not
|
||||
// what is meant. The invalid empty string is probably to
|
||||
// be interpreted as a missing field/value. Let's handle
|
||||
// this graceful.
|
||||
if (!empty($data)) {
|
||||
return new \DateTime($data);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} elseif (in_array($class, [
|
||||
'DateTime', 'bool', 'boolean', 'byte', 'double', 'float', 'int', 'integer', 'mixed', 'number', 'object',
|
||||
'string', 'void',
|
||||
], true)) {
|
||||
settype($data, $class);
|
||||
|
||||
return $data;
|
||||
} elseif (method_exists($class, 'getAllowableEnumValues')) {
|
||||
if (!in_array($data, $class::getAllowableEnumValues())) {
|
||||
$imploded = implode("', '", $class::getAllowableEnumValues());
|
||||
throw new \InvalidArgumentException("Invalid value for enum '$class', must be one of: '$imploded'");
|
||||
}
|
||||
|
||||
return $data;
|
||||
} else {
|
||||
// If a discriminator is defined and points to a valid subclass, use it.
|
||||
$discriminator = $class::DISCRIMINATOR;
|
||||
if (!empty($discriminator) && isset($data->{$discriminator}) && is_string($data->{$discriminator})) {
|
||||
$subclass = '\Yeepay\Yop\Sdk\\Model\\'.$data->{$discriminator};
|
||||
if (is_subclass_of($subclass, $class)) {
|
||||
$class = $subclass;
|
||||
}
|
||||
}
|
||||
$instance = new $class();
|
||||
foreach ($instance::swaggerTypes() as $property => $type) {
|
||||
$propertySetter = $instance::setters()[$property];
|
||||
|
||||
if (!isset($propertySetter) || !isset($data->{$instance::attributeMap()[$property]})) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$propertyValue = $data->{$instance::attributeMap()[$property]};
|
||||
if (isset($propertyValue)) {
|
||||
$instance->$propertySetter(self::deserialize($propertyValue, $type, null));
|
||||
}
|
||||
}
|
||||
|
||||
return $instance;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
23
lib/Utils/UUIDUtils.php
Normal file
23
lib/Utils/UUIDUtils.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Yeepay\Yop\Sdk\Utils;
|
||||
|
||||
class UUIDUtils
|
||||
{
|
||||
|
||||
public static function uuid($namespace = '')
|
||||
{
|
||||
$uid = uniqid("", true);
|
||||
$data = $_SERVER['REQUEST_TIME'];
|
||||
$hash = hash('ripemd128', $uid.$data);
|
||||
|
||||
$guid = $namespace.
|
||||
substr($uid, 0, 14).
|
||||
substr($uid, 15, 24).
|
||||
substr($hash, 0, 10).
|
||||
'';
|
||||
|
||||
return $guid;
|
||||
}
|
||||
|
||||
}
|
||||
22
lib/Utils/YopConstants.php
Normal file
22
lib/Utils/YopConstants.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Yeepay\Yop\Sdk\Utils;
|
||||
|
||||
class YopConstants
|
||||
{
|
||||
|
||||
const LANG = 'php';
|
||||
|
||||
const VERSION = "3.2.24";
|
||||
|
||||
const DEFAULT_ENCODING = "UTF-8";
|
||||
|
||||
const DEFAULT_SERVER_ROOT = "https://openapi.yeepay.com/yop-center";
|
||||
|
||||
const DEFAULT_YOS_SERVER_ROOT = "https://yos.yeepay.com/yop-center";
|
||||
|
||||
const DEFAULT_SANDBOX_SERVER_ROOT = "https://sandbox.yeepay.com/yop-center";
|
||||
|
||||
const DEFAULT_SANDBOX_VIA = "sandbox";
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user