如何解决此解码和语法错误
Posted
技术标签:
【中文标题】如何解决此解码和语法错误【英文标题】:How can I solve this decode and syntax error 【发布时间】:2020-12-26 05:56:56 【问题描述】:我的 php 脚本有问题。 (我和我的朋友写这篇文章对错误感到抱歉) 这是向我展示的错误:
致命错误:未捕获的 InvalidArgumentException:json_decode 错误: 语法错误 /opt/html/wordpress_eagle/forums/vendor/guzzlehttp/guzzle/src/functions.php:306 堆栈跟踪:#0 /opt/html/wordpress_eagle/forums/vendor/restcord/restcord/src/DiscordClient.php(229): GuzzleHttp\json_decode('')#1 /opt/html/wordpress_eagle/forums/vendor/restcord/restcord/src/DiscordClient.php(184): RestCord\DiscordClient->convertResponseToResult('guild', Array, 对象(GuzzleHttp\Psr7\Response),对象(GuzzleHttp\Command\Command)) #2 /opt/html/wordpress_eagle/forums/vendor/guzzlehttp/command/src/ServiceClient.php(215): RestCord\DiscordClient->RestCordclosure(对象(GuzzleHttp\Psr7\Response), 对象(GuzzleHttp\Psr7\Request),对象(GuzzleHttp\Command\Command)) #3 /opt/html/wordpress_eagle/forums/vendor/guzzlehttp/command/src/ServiceClient.php(177): GuzzleHttp\Command\ServiceClient->transformResponseToResult(对象(GuzzleHttp\Psr7\Response), 对象(GuzzleHttp\Psr7\Request),对象(GuzzleHttp\Command\Command)) #4 [内部函数]:/opt/html/wordpress_eagle/forums/vendor/guzzlehttp/command/src/Exception/CommandException.php 中的 GuzzleHtt 第 57 行
这是 json_decode 抛出错误 GuzzleHttp/src/functions.php 的地方: https://github.com/guzzle/guzzle/blob/4.1.0/src/functions.php#L305
*
* @param string $json JSON data to parse
* @param bool $assoc When true, returned objects will be converted
* into associative arrays.
* @param int $depth User specified recursion depth.
* @param int $options Bitmask of JSON decode options.
*
* @return mixed
* @throws \InvalidArgumentException if the JSON cannot be decoded.
* @link http://www.php.net/manual/en/function.json-decode.php
*/
function json_decode( $json, $assoc = false, $depth = 512, $options = 0) ### 306 line in function.php
$data = \json_decode($json, $assoc, $depth, $options);
if (JSON_ERROR_NONE !== json_last_error())
throw new \InvalidArgumentException(
'json_decode error: ' . json_last_error_msg()
);
return $data;
/**
* Wrapper for JSON encoding that throws when an error occurs.
*
* @param mixed $value The value being encoded
* @param int $options JSON encode option bitmask
* @param int $depth Set the maximum depth. Must be greater than zero.
*
* @return string
* @throws \InvalidArgumentException if the JSON cannot be encoded.
* @link http://www.php.net/manual/en/function.json-encode.php
*/
function json_encode($value, $options = 0, $depth = 512)
$json = \json_encode($value, $options, $depth);
if (JSON_ERROR_NONE !== json_last_error())
throw new \InvalidArgumentException(
'json_encode error: ' . json_last_error_msg()
);
return $json;
这是来自 commandexception.php 的行:
// Create the exception.
return new $class($message, $command, $prev, $request, $response); ### this is underlined like Fatal Error.
discordclient.php: ### restcord https://github.com/restcord/restcord/blob/master/src/DiscordClient.php
class DiscordClient
/**
* @var array
*/
private $options;
/**
* @var GuzzleClient[]
*/
private $categories = [];
/**
* @var Logger
*/
private $logger;
/**
* Client constructor.
*
* @param array $options
*/
public function __construct(array $options = [])
$this->options = $this->validateOptions($options);
$this->logger = $this->options['logger'];
$stack = HandlerStack::create();
$stack->push(
new RateLimiter(
$this->options['rateLimitProvider'],
$this->options,
$this->logger
)
);
$stack->push(
Middleware::log(
$this->logger,
new MessageFormatter('response', $this->options['token'])
)
);
$stack->push(
Middleware::log(
$this->logger,
new MessageFormatter('url request', $this->options['token'])
)
);
$defaultGuzzleOptions = [
'base_uri' => $this->options['apiUrl'],
'headers' => [
'Authorization' => $this->getAuthorizationHeader($this->options['tokenType'], $this->options['token']),
'User-Agent' => "DiscordBot (https://github.com/aequasi/php-restcord, $this->getVersion())",
'Content-Type' => 'application/json',
],
'http_errors' => isset($this->options['httpErrors']) ? $this->options['httpErrors'] : true,
'handler' => $stack,
];
$this->options['guzzleOptions'] = array_merge($this->options['guzzleOptions'], $defaultGuzzleOptions);
$client = new Client($this->options['guzzleOptions']);
$this->buildDescriptions($client);
/**
* @param string $name
*
* @throws \Exception
*
* @return GuzzleClient
*/
public function __get($name)
if (!isset($this->categories[$name]))
throw new \Exception('No category with the name: '.$name);
return $this->categories[$name];
/**
* @param array $options
*
* @return array
*/
private function validateOptions(array $options)
$currentVersion = 6;
$resolver = new OptionsResolver();
$resolver->setDefaults(
[
'version' => $currentVersion,
'logger' => new Logger('Logger'),
'rateLimitProvider' => new MemoryRateLimitProvider(),
'throwOnRatelimit' => false,
'apiUrl' => "https://discord.com/api/v$currentVersion/",
'tokenType' => 'Bot',
'cacheDir' => __DIR__.'/../../../cache/',
'guzzleOptions' => [],
]
)
->setDefined(['token'])
->setAllowedValues('tokenType', ['Bot', 'OAuth'])
->setAllowedTypes('token', ['string'])
->setAllowedTypes('apiUrl', ['string'])
->setAllowedTypes('rateLimitProvider', [AbstractRateLimitProvider::class])
->setAllowedTypes('throwOnRatelimit', ['bool'])
->setAllowedTypes('logger', ['\Psr\Log\LoggerInterface'])
->setAllowedTypes('version', ['string', 'integer'])
->setAllowedTypes('guzzleOptions', ['array']);
return $resolver->resolve($options);
/**
* @param Client $client
*/
private function buildDescriptions(Client $client)
$description = \GuzzleHttp\json_decode(
file_get_contents(__DIR__.'/Resources/service_description-v'.$this->options['version'].'.json'),
true
);
$base = [
'baseUri' => $this->options['apiUrl'],
'version' => $description['version'],
'models' => $this->prepareModels($description['models']),
];
foreach ($description['operations'] as $category => $operations)
$this->categories[$category] = new OverriddenGuzzleClient(
$client,
new Description(array_merge($base, ['operations' => $this->prepareOperations($operations)])),
function ($res, $req, $com) use ($category, $description)
return $this->convertResponseToResult($category, $description, $res, $com);
,
$category
);
/**
* @param string $category
* @param array $description
* @param ResponseInterface $response
* @param CommandInterface $command
*
* @throws \Exception
*
* @return Result|mixed
*
* @internal param RequestInterface $request
*/
private function convertResponseToResult(
$category,
array $description,
ResponseInterface $response,
CommandInterface $command
)
if ($response->getStatusCode() >= 400)
throw new \Exception($response->getBody()->__toString(), $response->getStatusCode());
$operation = $description['operations'][$category][$command->getName()];
if (!isset($operation['responseTypes']) || count($operation['responseTypes']) === 0)
try
$content = $response->getBody()->__toString();
if (empty($content))
$content = '';
return new Result(json_decode($content, true));
catch (\Exception $e)
dump($response->getBody()->__toString());
throw $e;
$data = json_decode($response->getBody()->__toString());
$array = strpos($operation['responseTypes'][0]['type'], 'Array') !== false;
$responseType = $operation['responseTypes'][0]['type'];
if ($array)
$matches = [];
preg_match('/Array<(.+)>/', $responseType, $matches);
$responseType = $matches[1];
$firstType = explode('/', $this->dashesToCamelCase($responseType, true));
$class = $this->mapBadDocs(
sprintf(
'\\RestCord\\Model\\%s\\%s',
ucwords($firstType[0]),
ucwords($firstType[1])
)
);
if (!class_exists($class))
return new Result($data);
if ($data === null)
return new Result([]);
$mapper = new \JsonMapper();
$mapper->bStrictNullTypes = false;
if ($array)
return array_map(
function ($item) use ($class, $mapper)
return $mapper->map($item, new $class());
,
$data
);
return $mapper->map($data, new $class());
private function dashesToCamelCase($string, $capitalizeFirstCharacter = false)
$str = str_replace(' ', '', ucwords(str_replace('-', ' ', $string)));
if (!$capitalizeFirstCharacter)
$str[0] = strtolower($str[0]);
return $str;
private function mapBadDocs($cls)
switch ($cls)
case 'Channel\Invite':
case '\RestCord\Model\Channel\Invite':
case '\RestCord\Model\Guild\Invite':
return '\RestCord\Model\Invite\Invite';
case '\RestCord\Model\Guild\GuildChannel':
return '\RestCord\Model\Channel\GuildChannel';
case '\RestCord\Model\Guild\User':
case '\RestCord\Model\Channel\User':
return '\RestCord\Model\User\User';
default:
return $cls;
/**
* @param array $operations
*
* @return array
*/
private function prepareOperations(array $operations)
foreach ($operations as $operation => &$config)
$config['uri'] = ltrim($config['url'], '/');
unset($config['url']);
$config['httpMethod'] = strtoupper($config['method']);
unset($config['method']);
if (isset($config['responseTypes']) && count($config['responseTypes']) === 1)
$class = ucwords($config['resource']).'\\';
$class .= str_replace(' ', '', ucwords($config['responseTypes'][0]['name']));
$config['responseModel'] = $class;
else
$config['responseModel'] = 'getResponse';
if (isset($config['parametersArray']) && $config['parametersArray'])
$config['type'] = 'array';
unset($config['parametersArray']);
foreach ($config['parameters'] as $parameter => &$parameterConfig)
$this->updateParameterTypes($parameterConfig);
if (!isset($parameterConfig['required']))
$parameterConfig['required'] = false;
return $operations;
/**
* @param array $parameterConfig
*/
private function updateParameterTypes(array &$parameterConfig)
if ($parameterConfig['type'] === 'snowflake')
$parameterConfig['type'] = 'integer';
if ($parameterConfig['type'] === 'bool')
$parameterConfig['type'] = 'boolean';
if ($parameterConfig['type'] === 'file contents')
$parameterConfig['type'] = 'string';
if (stripos($parameterConfig['type'], 'object') !== false)
$parameterConfig['type'] = 'array';
/**
* @return string
*/
private function getVersion()
return trim(file_get_contents(__DIR__.'/../VERSION'));
/**
* @param array $toParse
*
* @return array|mixed
*/
private function prepareModels(array $toParse)
$models = [
'getResponse' => [
'type' => 'object',
'additionalProperties' => [
'location' => 'json',
],
],
];
foreach ($toParse as $category => $m)
foreach ($m as $name => $model)
$class = ucwords($category).'\\'.ucwords($name);
$models[$class] = [
'type' => 'object',
'properties' => [],
'additionalProperties' => [
'location' => 'json',
],
];
foreach ($model['properties'] as $n => $property)
if ($property['type'] !== 'array' && $property['type'] !== 'object')
$models[$class]['properties'][$n] = [
'type' => $property['type'],
'location' => 'json',
];
// Maps!
$models['Guild\\Channel'] = $models['Channel\\Channel'];
return $models;
/**
* @param string $tokenType
* @param string $token
*
* @return string
*/
private function getAuthorizationHeader($tokenType, $token)
switch ($tokenType)
default:
$authorization = 'Bot ';
break;
case 'OAuth':
$authorization = 'Bearer ';
return $authorization.$token;
对于 __DIR__.'/Resources/service_description-v'.$this->options['version'].'.json'
json 文件,请参阅 pastebin https://pastebin.com/hZURQJkD
【问题讨论】:
其中哪一行是第 306 行? 该错误似乎不一定是因为 GuzzleHttp 而发生,而是因为您的“restcord”库试图将空字符串解码为有效的 JSON。 你为什么要命名json_decode
?
对不起,我不知道,这个脚本是我朋友写的。
@fyrye,谢谢现在它正在工作,我使用的是旧的 api。我刚刚用新的restcord替换了旧的restcord,现在它正在工作。谢谢。
【参考方案1】:
解决方案:我使用的是旧的 api,我用新的 restcord 替换了旧的 restcord,现在一切正常。
【讨论】:
以上是关于如何解决此解码和语法错误的主要内容,如果未能解决你的问题,请参考以下文章
如何解决 MySql 中的 PARTITION BY 语法错误