Get MIME-type by URL - php

Fore example exif_imagetype() works fine
<?php echo exif_imagetype('http://orig01.deviantart.net/ace1/f/2010/227/4/6/png_test_by_destron23.png');
But finfo_file() does not work.
<?php echo finfo_file(finfo_open(FILEINFO_MIME), 'http://orig01.deviantart.net/ace1/f/2010/227/4/6/png_test_by_destron23.png');
and got
Warning: finfo_file(): Failed identify data 0:(null) in /test.php on line 1
Any thoughts?

It is need to stream_wrapper_register()
class MimeStreamWrapper
{
const WRAPPER_NAME = 'mime';
/**
* #var resource
*/
public $context;
/**
* #var bool
*/
private static $isRegistered = false;
/**
* #var callable
*/
private $callBackFunction;
/**
* #var bool
*/
private $eof = false;
/**
* #var resource
*/
private $fp;
/**
* #var string
*/
private $path;
/**
* #var array
*/
private $fileStat;
/**
* #return array
*/
private function getStat()
{
if ($fStat = fstat($this->fp)) {
return $fStat;
}
$size = 100;
if ($headers = get_headers($this->path, true)) {
$head = array_change_key_case($headers, CASE_LOWER);
$size = (int)$head['content-length'];
}
$blocks = ceil($size / 512);
return array(
'dev' => 16777220,
'ino' => 15764,
'mode' => 33188,
'nlink' => 1,
'uid' => 10000,
'gid' => 80,
'rdev' => 0,
'size' => $size,
'atime' => 0,
'mtime' => 0,
'ctime' => 0,
'blksize' => 4096,
'blocks' => $blocks,
);
}
/**
* #param string $path
*/
public function setPath($path)
{
$this->path = $path;
$this->fp = fopen($this->path, 'rb') or die('Cannot open file: ' . $this->path);
$this->fileStat = $this->getStat();
}
/**
* #param int $count
* #return string
*/
public function read($count) {
return fread($this->fp, $count);
}
/**
* #return string
*/
public function getStreamPath()
{
return str_replace(array('ftp://', 'http://', 'https://'), self::WRAPPER_NAME . '://', $this->path);
}
/**
* #return resource
*/
public function getContext()
{
if (!self::$isRegistered) {
stream_wrapper_register(self::WRAPPER_NAME, get_class());
self::$isRegistered = true;
}
return stream_context_create(
array(
self::WRAPPER_NAME => array(
'cb' => array($this, 'read'),
'fileStat' => $this->fileStat,
)
)
);
}
/**
* #param $path
* #param $mode
* #param $options
* #param $opened_path
* #return bool
*/
public function stream_open($path, $mode, $options, &$opened_path)
{
if (!preg_match('/^r[bt]?$/', $mode) || !$this->context) {
return false;
}
$opt = stream_context_get_options($this->context);
if (!is_array($opt[self::WRAPPER_NAME]) ||
!isset($opt[self::WRAPPER_NAME]['cb']) ||
!is_callable($opt[self::WRAPPER_NAME]['cb'])
) {
return false;
}
$this->callBackFunction = $opt[self::WRAPPER_NAME]['cb'];
$this->fileStat = $opt[self::WRAPPER_NAME]['fileStat'];
return true;
}
/**
* #param int $count
* #return mixed|string
*/
public function stream_read($count)
{
if ($this->eof || !$count) {
return '';
}
if (($s = call_user_func($this->callBackFunction, $count)) == '') {
$this->eof = true;
}
return $s;
}
/**
* #return bool
*/
public function stream_eof()
{
return $this->eof;
}
/**
* #return array
*/
public function stream_stat()
{
return $this->fileStat;
}
/**
* #param int $castAs
*
* #return resource
*/
public function stream_cast($castAs)
{
$read = null;
$write = null;
$except = null;
return #stream_select($read, $write, $except, $castAs);
}
}
//$path = 'ftp://ftp.happy.kiev.ua/pub/pictures/ksyu/15.TIF';
//$path = 'ftp://ftp.happy.kiev.ua/pub/pictures/arcwolf1.gif';
//$path = 'ftp://ftp.happy.kiev.ua/pub/pictures/pub_k.pcx';
//$path = 'ftp://ftp.happy.kiev.ua/pub/pictures/9427.jpg';
//$path = 'https://homepages.cae.wisc.edu/~ece533/images/airplane.png';
//$path = '/etc/hosts';
$path = 'http://fc04.deviantart.net/fs71/f/2010/227/4/6/PNG_Test_by_Destron23.png';
echo "File: ", $path, "\n";
$wrapper = new MimeStreamWrapper();
$wrapper->setPath($path);
$fInfo = new finfo(FILEINFO_MIME);
echo "MIME-type: ", $fInfo->file($wrapper->getStreamPath(), FILEINFO_MIME_TYPE, $wrapper->getContext()), "\n";

Related

How can I solve this decode and syntax error

I have problem with my php script.
( My friend and I write this sorry for mistakes )
This is error that shows me :
Fatal error: Uncaught InvalidArgumentException: json_decode error:
Syntax error in
/opt/html/wordpress_eagle/forums/vendor/guzzlehttp/guzzle/src/functions.php:306
Stack trace:#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,
Object(GuzzleHttp\Psr7\Response), Object(GuzzleHttp\Command\Command))
#2 /opt/html/wordpress_eagle/forums/vendor/guzzlehttp/command/src/ServiceClient.php(215):
RestCord\DiscordClient->RestCord{closure}(Object(GuzzleHttp\Psr7\Response),
Object(GuzzleHttp\Psr7\Request), Object(GuzzleHttp\Command\Command))
#3 /opt/html/wordpress_eagle/forums/vendor/guzzlehttp/command/src/ServiceClient.php(177):
GuzzleHttp\Command\ServiceClient->transformResponseToResult(Object(GuzzleHttp\Psr7\Response),
Object(GuzzleHttp\Psr7\Request), Object(GuzzleHttp\Command\Command))
#4 [internal function]: GuzzleHtt in /opt/html/wordpress_eagle/forums/vendor/guzzlehttp/command/src/Exception/CommandException.php
on line 57
This is where json_decode throws the error 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;
And this is line from 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;
}
}
For the __DIR__.'/Resources/service_description-v'.$this->options['version'].'.json' json file see the pastebin https://pastebin.com/hZURQJkD
Solution : I was using old api, I replaced old restcord for new restcord and now everything working.

Symfony 4 custom deserializer returns empty properties in entity

I have a custom Symfony 4 deserializer
class CardImageDecoder implements EncoderInterface, DecoderInterface
{
public function encode($data, $format, array $context = [])
{
if($format !== 'json') {
throw new EncodingFormatNotSupportedException(sprintf('Format %s is not supported by encoder %s', $format, __CLASS__));
}
$result = json_encode($data);
if(json_last_error() !== JSON_ERROR_NONE) {
// don't bother with a custom error message
throw new \Exception(sprintf('Unable to encode data, got error message: %s', json_last_error_msg()));
}
return $result;
}
public function supportsEncoding($format)
{
return 'json' === $format;
}
public function decode($data, $format, array $context = [])
{
if($format !== 'array') {
throw new DecodingFormatNotSupportedException(sprintf('Format %s is not supported by encoder %s', $format, __CLASS__));
}
if(!is_array($data)) {
throw new \UnexpectedValueException(sprintf('Expected array got %s', gettype($data)));
}
$cardInstance = new CardImages();
$cardInstance->setHeight($data['h'] ?? 0);
$cardInstance->setPath($data['url'] ?? '');
$cardInstance->setWidth($data['w'] ?? 0);
return $cardInstance;
}
public function supportsDecoding($format)
{
return 'array' === $format;
}
}
The way I'm deserializing is pretty straight forward:
$json = '
{
"url": "some url",
"h": 1004,
"w": 768
}';
$encoders = [new CardImageDecoder()];
$normalizers = [new ObjectNormalizer()];
$serializer = new Serializer($normalizers, $encoders);
$cardImage = $serializer->deserialize(json_decode($json, true), CardImages::class, 'array');
/** #var $cardImage CardImages */
var_dump($cardImage);
However, I get this result returned:
object(App\Entity\CardImages)#158 (5) {
["id":"App\Entity\CardImages":private]=>
NULL
["path":"App\Entity\CardImages":private]=>
NULL
["height":"App\Entity\CardImages":private]=>
NULL
["width":"App\Entity\CardImages":private]=>
NULL
["movie":"App\Entity\CardImages":private]=>
NULL
}
Now, if I were to do a dump, just before the return in the decode part of the decoder, I'd get this:
...
$cardInstance->setWidth($data['w'] ?? 0);
var_dump($cardInstance);
object(App\Entity\CardImages)#153 (5) {
["id":"App\Entity\CardImages":private]=>
NULL
["path":"App\Entity\CardImages":private]=>
string(8) "some url"
["height":"App\Entity\CardImages":private]=>
int(1004)
["width":"App\Entity\CardImages":private]=>
int(768)
["movie":"App\Entity\CardImages":private]=>
NULL
}
Ignoring the not set properties(which I'm fine with), it should work quite nicely, but it doesn't.
For the life of me I can't figure out what's wrong.
Any help is appreciated.
You are thinking way to complicated.
Tested, working example:
Your entity - take a closer look at the end - we need setters with the names of your array keys:
namespace App\Domain;
class CardImages
{
/** #var int|null */
private $id;
/** #var int|null */
private $height;
/** #var string|null */
private $path;
/** #var int|null */
private $width;
/** #var mixed */
private $movie;
/**
* #return int|null
*/
public function getId(): ?int
{
return $this->id;
}
/**
* #param int|null $id
* #return CardImages
*/
public function setId(?int $id): CardImages
{
$this->id = $id;
return $this;
}
/**
* #return int|null
*/
public function getHeight(): ?int
{
return $this->height;
}
/**
* #param int|null $height
* #return CardImages
*/
public function setHeight(?int $height): CardImages
{
$this->height = $height;
return $this;
}
/**
* #return string|null
*/
public function getPath(): ?string
{
return $this->path;
}
/**
* #param string|null $path
* #return CardImages
*/
public function setPath(?string $path): CardImages
{
$this->path = $path;
return $this;
}
/**
* #return int|null
*/
public function getWidth(): ?int
{
return $this->width;
}
/**
* #param int|null $width
* #return CardImages
*/
public function setWidth(?int $width): CardImages
{
$this->width = $width;
return $this;
}
/**
* #return mixed
*/
public function getMovie()
{
return $this->movie;
}
/**
* #param mixed $movie
* #return CardImages
*/
public function setMovie($movie)
{
$this->movie = $movie;
return $this;
}
public function setH(?int $height): CardImages
{
$this->setHeight($height);
return $this;
}
public function setUrl(?string $url): CardImages
{
$this->setPath($url);
return $this;
}
public function setW(?int $width): CardImages
{
$this->setWidth($width);
return $this;
}
}
Simple Controller to test the Output:
<?php
namespace App\Infrastructure\Web\Controller;
use App\Domain\CardImages;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\SerializerInterface;
/**
* Class IndexController.
*
* #Route("/test")
*/
class TestController extends AbstractController
{
private $serializer;
public function __construct(SerializerInterface $serializer)
{
$this->serializer = $serializer;
}
/**
* #Route("")
*
* #return Response
*/
public function indexAction(): Response
{
$data = [
[
'h' => 100,
'w' => 100,
'path' => '/asdf/asdf.png',
],
[
'h' => 50,
'w' => 150,
'path' => '/asdf/foo.png',
],
[
'h' => 100,
'w' => 200,
'path' => '/asdf/bar.png',
],
[
'h' => 300,
'w' => 400,
'path' => '/asdf/baz.png',
],
];
foreach ($data as $row) {
$cardImage = $this->serializer->denormalize($row, CardImages::class, null, [
ObjectNormalizer::DISABLE_TYPE_ENFORCEMENT => false
]);
$json = $this->serializer->serialize($cardImage, 'json');
dump($cardImage, $json);
}
return new Response('<html><head></head></html></body></html>');
}
}
Output:

PHP API Call function is not working

I have a Question about calling a other script.
I want to make an api whit ExactOnline... But i need to call an other script for that I used "require DIR ." That works fine but my code still doesn't get the script. Can someone explane to me why this is not working?
(My script that need to call is in "C:\xampp\htdocs\CM\EO\exactphpclientmaster\vendor\picqer\exactphpclient\src\Picqer\Financials\Exact\Connection.php")
=ERROR=
Fatal error: Class 'vendor\picqer\exactphpclient\src\Picqer\Financials\Exact\Connection' not found in C:\xampp\htdocs\CM\EO\exactphpclientmaster\ConntectEO.php on line 3
=SCRIPT That is calling connection.php=
<?php
require __DIR__ . '\vendor\picqer\exactphpclient\src\Picqer\Financials\Exact\Connection.php';
$connection = new \vendor\picqer\exactphpclient\src\Picqer\Financials\Exact\Connection.php();
$connection->setRedirectUrl('**************************'); // Same as entered online in the App Center
$connection->setExactClientId('****************************************');
$connection->setExactClientSecret('************************');
if (getValue('authorizationcode')) // Retrieves authorizationcode from database
$connection->setAuthorizationCode(getValue('authorizationcode'));
if (getValue('accesstoken')) // Retrieves accesstoken from database
$connection->setAccessToken(unserialize(getValue('accesstoken')));
if (getValue('refreshtoken')) // Retrieves refreshtoken from database
$connection->setRefreshToken(getValue('refreshtoken'));
if (getValue('expires_in')) // Retrieves expires timestamp from database
$connection->setTokenExpires(getValue('expires_in'));
// Make the client connect and exchange tokens
try {
$connection->connect();
} catch (\Exception $e)
{
throw new Exception('Could not connect to Exact: ' . $e->getMessage());
}
// Save the new tokens for next connections
setValue('accesstoken', serialize($connection->getAccessToken()));
setValue('refreshtoken', $connection->getRefreshToken());
// Optionally, save the expiry-timestamp. This prevents exchanging valid tokens (ie. saves you some requests)
setValue('expires_in', $connection->getTokenExpires());
=SCRIPT Connection.php=
<?php namespace Picqer\Financials\Exact;
use Exception;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\BadResponseException;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\Response;
use GuzzleHttp\Psr7;
/**
* Class Connection
*
* #package Picqer\Financials\Exact
*
*/
class Connection
{
/**
* #var string
*/
private $baseUrl = 'https://start.exactonline.nl';
/**
* #var string
*/
private $apiUrl = '/api/v1';
/**
* #var string
*/
private $authUrl = '/api/oauth2/auth';
/**
* #var string
*/
private $tokenUrl = '/api/oauth2/token';
/**
* #var
*/
private $exactClientId;
/**
* #var
*/
private $exactClientSecret;
/**
* #var
*/
private $authorizationCode;
/**
* #var
*/
private $accessToken;
/**
* #var
*/
private $tokenExpires;
/**
* #var
*/
private $refreshToken;
/**
* #var
*/
private $redirectUrl;
/**
* #var
*/
private $division;
/**
* #var Client
*/
private $client;
/**
* #var callable(Connection)
*/
private $tokenUpdateCallback;
/**
*
*/
protected $middleWares = [];
/**
* #var
*/
public $nextUrl = null;
/**
* #return Client
*/
private function client()
{
if ($this->client) {
return $this->client;
}
$handlerStack = HandlerStack::create();
foreach ($this->middleWares as $middleWare) {
$handlerStack->push($middleWare);
}
$this->client = new Client([
'http_errors' => true,
'handler' => $handlerStack,
'expect' => false,
]);
return $this->client;
}
public function insertMiddleWare($middleWare)
{
$this->middleWares[] = $middleWare;
}
public function connect()
{
// Redirect for authorization if needed (no access token or refresh token given)
if ($this->needsAuthentication()) {
$this->redirectForAuthorization();
}
// If access token is not set or token has expired, acquire new token
if (empty($this->accessToken) || $this->tokenHasExpired()) {
$this->acquireAccessToken();
}
$client = $this->client();
return $client;
}
/**
* #param string $method
* #param $endpoint
* #param null $body
* #param array $params
* #param array $headers
* #return Request
*/
private function createRequest($method = 'GET', $endpoint, $body = null, array $params = [], array $headers = [])
{
// Add default json headers to the request
$headers = array_merge($headers, [
'Accept' => 'application/json',
'Content-Type' => 'application/json',
'Prefer' => 'return=representation'
]);
// If access token is not set or token has expired, acquire new token
if (empty($this->accessToken) || $this->tokenHasExpired()) {
$this->acquireAccessToken();
}
// If we have a token, sign the request
if (!$this->needsAuthentication() && !empty($this->accessToken)) {
$headers['Authorization'] = 'Bearer ' . $this->accessToken;
}
// Create param string
if (!empty($params)) {
$endpoint .= '?' . http_build_query($params);
}
// Create the request
$request = new Request($method, $endpoint, $headers, $body);
return $request;
}
/**
* #param $url
* #param array $params
* #return mixed
* #throws ApiException
*/
public function get($url, array $params = [])
{
$url = $this->formatUrl($url, $url !== 'current/Me', $url == $this->nextUrl);
try {
$request = $this->createRequest('GET', $url, null, $params);
$response = $this->client()->send($request);
return $this->parseResponse($response, $url != $this->nextUrl);
} catch (Exception $e) {
$this->parseExceptionForErrorMessages($e);
}
}
/**
* #param $url
* #param $body
* #return mixed
* #throws ApiException
*/
public function post($url, $body)
{
$url = $this->formatUrl($url);
try {
$request = $this->createRequest('POST', $url, $body);
$response = $this->client()->send($request);
return $this->parseResponse($response);
} catch (Exception $e) {
$this->parseExceptionForErrorMessages($e);
}
}
/**
* #param $url
* #param $body
* #return mixed
* #throws ApiException
*/
public function put($url, $body)
{
$url = $this->formatUrl($url);
try {
$request = $this->createRequest('PUT', $url, $body);
$response = $this->client()->send($request);
return $this->parseResponse($response);
} catch (Exception $e) {
$this->parseExceptionForErrorMessages($e);
}
}
/**
* #param $url
* #return mixed
* #throws ApiException
*/
public function delete($url)
{
$url = $this->formatUrl($url);
try {
$request = $this->createRequest('DELETE', $url);
$response = $this->client()->send($request);
return $this->parseResponse($response);
} catch (Exception $e) {
$this->parseExceptionForErrorMessages($e);
}
}
/**
* #return string
*/
public function getAuthUrl()
{
return $this->baseUrl . $this->authUrl . '?' . http_build_query(array(
'client_id' => $this->exactClientId,
'redirect_uri' => $this->redirectUrl,
'response_type' => 'code'
));
}
/**
* #param mixed $exactClientId
*/
public function setExactClientId($exactClientId)
{
$this->exactClientId = $exactClientId;
}
/**
* #param mixed $exactClientSecret
*/
public function setExactClientSecret($exactClientSecret)
{
$this->exactClientSecret = $exactClientSecret;
}
/**
* #param mixed $authorizationCode
*/
public function setAuthorizationCode($authorizationCode)
{
$this->authorizationCode = $authorizationCode;
}
/**
* #param mixed $accessToken
*/
public function setAccessToken($accessToken)
{
$this->accessToken = $accessToken;
}
/**
* #param mixed $refreshToken
*/
public function setRefreshToken($refreshToken)
{
$this->refreshToken = $refreshToken;
}
/**
*
*/
public function redirectForAuthorization()
{
$authUrl = $this->getAuthUrl();
header('Location: ' . $authUrl);
exit;
}
/**
* #param mixed $redirectUrl
*/
public function setRedirectUrl($redirectUrl)
{
$this->redirectUrl = $redirectUrl;
}
/**
* #return bool
*/
public function needsAuthentication()
{
return empty($this->refreshToken) && empty($this->authorizationCode);
}
/**
* #param Response $response
* #param bool $returnSingleIfPossible
* #return mixed
* #throws ApiException
*/
private function parseResponse(Response $response, $returnSingleIfPossible = true)
{
try {
if ($response->getStatusCode() === 204) {
return [];
}
Psr7\rewind_body($response);
$json = json_decode($response->getBody()->getContents(), true);
if (array_key_exists('d', $json)) {
if (array_key_exists('__next', $json['d'])) {
$this->nextUrl = $json['d']['__next'];
}
else {
$this->nextUrl = null;
}
if (array_key_exists('results', $json['d'])) {
if ($returnSingleIfPossible && count($json['d']['results']) == 1) {
return $json['d']['results'][0];
}
return $json['d']['results'];
}
return $json['d'];
}
return $json;
} catch (\RuntimeException $e) {
throw new ApiException($e->getMessage());
}
}
/**
* #return mixed
*/
private function getCurrentDivisionNumber()
{
if (empty($this->division)) {
$me = new Me($this);
$this->division = $me->find()->CurrentDivision;
}
return $this->division;
}
/**
* #return mixed
*/
public function getRefreshToken()
{
return $this->refreshToken;
}
/**
* #return mixed
*/
public function getAccessToken()
{
return $this->accessToken;
}
private function acquireAccessToken()
{
// If refresh token not yet acquired, do token request
if (empty($this->refreshToken)) {
$body = [
'form_params' => [
'redirect_uri' => $this->redirectUrl,
'grant_type' => 'authorization_code',
'client_id' => $this->exactClientId,
'client_secret' => $this->exactClientSecret,
'code' => $this->authorizationCode
]
];
} else { // else do refresh token request
$body = [
'form_params' => [
'refresh_token' => $this->refreshToken,
'grant_type' => 'refresh_token',
'client_id' => $this->exactClientId,
'client_secret' => $this->exactClientSecret,
]
];
}
$response = $this->client()->post($this->getTokenUrl(), $body);
if ($response->getStatusCode() == 200) {
Psr7\rewind_body($response);
$body = json_decode($response->getBody()->getContents(), true);
if (json_last_error() === JSON_ERROR_NONE) {
$this->accessToken = $body['access_token'];
$this->refreshToken = $body['refresh_token'];
$this->tokenExpires = $this->getDateTimeFromExpires($body['expires_in']);
if (is_callable($this->tokenUpdateCallback)) {
call_user_func($this->tokenUpdateCallback, $this);
}
} else {
throw new ApiException('Could not acquire tokens, json decode failed. Got response: ' . $response->getBody()->getContents());
}
} else {
throw new ApiException('Could not acquire or refresh tokens');
}
}
private function getDateTimeFromExpires($expires)
{
if (!is_numeric($expires)) {
throw new \InvalidArgumentException('Function requires a numeric expires value');
}
return time() + 600;
}
/**
* #return mixed
*/
public function getTokenExpires()
{
return $this->tokenExpires;
}
/**
* #param mixed $tokenExpires
*/
public function setTokenExpires($tokenExpires)
{
$this->tokenExpires = $tokenExpires;
}
private function tokenHasExpired()
{
if (empty($this->tokenExpires)) {
return true;
}
return $this->tokenExpires <= time() + 10;
}
private function formatUrl($endPoint, $includeDivision = true, $formatNextUrl = false)
{
if ($formatNextUrl) {
return $endPoint;
}
if ($includeDivision) {
return implode('/', [
$this->getApiUrl(),
$this->getCurrentDivisionNumber(),
$endPoint
]);
}
return implode('/', [
$this->getApiUrl(),
$endPoint
]);
}
/**
* #return mixed
*/
public function getDivision()
{
return $this->division;
}
/**
* #param mixed $division
*/
public function setDivision($division)
{
$this->division = $division;
}
/**
* #param callable $callback
*/
public function setTokenUpdateCallback($callback) {
$this->tokenUpdateCallback = $callback;
}
/**
* Parse the reponse in the Exception to return the Exact error messages
* #param Exception $e
* #throws ApiException
*/
private function parseExceptionForErrorMessages(Exception $e)
{
if (! $e instanceof BadResponseException) {
throw new ApiException($e->getMessage());
}
$response = $e->getResponse();
Psr7\rewind_body($response);
$responseBody = $response->getBody()->getContents();
$decodedResponseBody = json_decode($responseBody, true);
if (! is_null($decodedResponseBody) && isset($decodedResponseBody['error']['message']['value'])) {
$errorMessage = $decodedResponseBody['error']['message']['value'];
} else {
$errorMessage = $responseBody;
}
throw new ApiException('Error ' . $response->getStatusCode() .': ' . $errorMessage);
}
/**
* #return string
*/
protected function getBaseUrl()
{
return $this->baseUrl;
}
/**
* #return string
*/
private function getApiUrl()
{
return $this->baseUrl . $this->apiUrl;
}
/**
* #return string
*/
private function getTokenUrl()
{
return $this->baseUrl . $this->tokenUrl;
}
/**
* Set base URL for different countries according to
* https://developers.exactonline.com/#Exact%20Online%20sites.html
*
* #param string $baseUrl
*/
public function setBaseUrl($baseUrl)
{
$this->baseUrl = $baseUrl;
}
/**
* #param string $apiUrl
*/
public function setApiUrl($apiUrl)
{
$this->apiUrl = $apiUrl;
}
/**
* #param string $authUrl
*/
public function setAuthUrl($authUrl)
{
$this->authUrl = $authUrl;
}
/**
* #param string $tokenUrl
*/
public function setTokenUrl($tokenUrl)
{
$this->tokenUrl = $tokenUrl;
}
}
The error itself is pretty self-explanatory. You are trying to include a file and it cannot be found with the path you provided.
Try printing what the magic constant __DIR__ contains in order to see the full path you are trying to include.
You can use var_dump(__DIR__);exit; at the start of your script.
As an additional note, you should consider using composer's autoload.
As you mention your trying to load Connection class as below
require __DIR__ . '\vendor\picqer\exactphpclient\src\Picqer\Financials\Exact\Connection.php';
When we using composer, instead of loading individual class files try to use composer auto load, its automatically loads the name spaces of the required class.
If you implement auto load in your code, the code may look like this.
require __DIR__ . '/vendor/autoload.php';
use Picqer\Financials\Exact\Connection;
$connection = new Connection();

How to disable _PHCR key pefixes used in Phalcon Redis backend

I'm using Phalcon Redis backend to store some data. I later try to access this data in Lua language embedded into nginx. What drives me crazy is that Phalcon adds some garbage prefixes to Redis keys and some terrible prefixes to values. So, if I store this pair in Redis - (abc, querty) - this is what is really stored:
(_PHCRabc, s:6:"querty")
Is it possible to disable all this garbage and continue working with Phalcon Redis backend?
According to the the source it is not possible to disable it with option: https://github.com/phalcon/cphalcon/blob/master/phalcon/cache/backend/redis.zep
public function get(string keyName, int lifetime = null) -> var | null
let lastKey = "_PHCR" . prefix . keyName;
public function save(keyName = null, content = null, lifetime = null, boolean stopBuffer = true) -> boolean
lastKey = "_PHCR" . prefixedKey,
Also quoting the docs:
This adapter uses the special redis key “_PHCR” to store all the keys
internally used by the adapter
I read somewhere that this is done in order to be able to flush Phalcon generated cache files.
Your best option would be to extend the \Phalcon\Cache\Backend\Redis class and overwrite the save/get methods. And after use your class in the service:
// Cache
$di->setShared('cache', function() use ($config) {
return new MyCustomRedis(
new \Phalcon\Cache\Frontend\Json(['lifetime' => 172800]), // 2d
$config->redis
);
});
You can override the redis adapter like this.
<?php
namespace App\Library\Cache\Backend;
use Phalcon\Cache\Exception;
class Redis extends \Phalcon\Cache\Backend\Redis
{
/**
* #var \Redis
*/
protected $_redis;
/**
* {#inheritdoc}
*
* #param string $keyName
* #param integer $lifetime
* #return mixed|null
*/
public function get($keyName, $lifetime = null)
{
$redis = $this->getRedis();
/**
* #var \Phalcon\Cache\FrontendInterface $frontend
*/
$frontend = $this->_frontend;
$lastKey = $this->getKeyName($keyName);
$this->_lastKey = $lastKey;
$content = $redis->get($lastKey);
if ($content === false) {
return null;
}
if (is_numeric($content)) {
return $content;
}
return $frontend->afterRetrieve($content);
}
/**
* {#inheritdoc}
*
* #param string $keyName
* #param string $content
* #param int $lifetime
* #param bool $stopBuffer
* #return bool
*
* #throws Exception
*/
public function save($keyName = null, $content = null, $lifetime = null, $stopBuffer = true)
{
if ($keyName === null) {
$lastKey = $this->_lastKey;
} else {
$lastKey = $this->getKeyName($keyName);
$this->_lastKey = $lastKey;
}
if (!$lastKey) {
throw new Exception('The cache must be started first');
}
$redis = $this->getRedis();
/**
* #var \Phalcon\Cache\FrontendInterface $frontend
*/
$frontend = $this->_frontend;
if ($content === null) {
$cachedContent = $frontend->getContent();
} else {
$cachedContent = $content;
}
/**
* Prepare the content in the frontend
*/
if (!is_numeric($cachedContent)) {
$preparedContent = $frontend->beforeStore($cachedContent);
} else {
$preparedContent = $cachedContent;
}
if ($lifetime === null) {
$tmp = $this->_lastLifetime;
$ttl = $tmp ? $tmp : $frontend->getLifetime();
} else {
$ttl = $lifetime;
}
$success = $redis->set($lastKey, $preparedContent);
if (!$success) {
throw new Exception('Failed storing the data in redis');
}
if ($ttl > 0) {
$redis->setTimeout($lastKey, $ttl);
}
$isBuffering = $frontend->isBuffering();
if ($stopBuffer === true) {
$frontend->stop();
}
if ($isBuffering === true) {
echo $cachedContent;
}
$this->_started = false;
return $success;
}
/**
* {#inheritdoc}
*
* #param string $keyName
* #return bool
*/
public function delete($keyName)
{
$redis = $this->getRedis();
$lastKey = $this->getKeyName($keyName);
return (bool)$redis->delete($lastKey);
}
/**
* {#inheritdoc}
*
* #param string $prefix
* #return array
*/
public function queryKeys($prefix = null)
{
$redis = $this->getRedis();
$pattern = "{$this->_prefix}" . ($prefix ? $prefix : '') . '*';
return $redis->keys($pattern);
}
/**
* {#inheritdoc}
*
* #param string $keyName
* #param string $lifetime
* #return bool
*/
public function exists($keyName = null, $lifetime = null)
{
$redis = $this->getRedis();
if ($keyName === null) {
$lastKey = $this->_lastKey;
} else {
$lastKey = $this->getKeyName($keyName);
}
return (bool)$redis->exists($lastKey);
}
/**
* {#inheritdoc}
*
* #param string $keyName
* #param int $value
* #return int
*/
public function increment($keyName = null, $value = 1)
{
$redis = $this->getRedis();
if ($keyName === null) {
$lastKey = $this->_lastKey;
} else {
$lastKey = $this->getKeyName($keyName);
}
return $redis->incrBy($lastKey, $value);
}
/**
* {#inheritdoc}
*
* #param string $keyName
* #param int $value
* #return int
*/
public function decrement($keyName = null, $value = 1)
{
$redis = $this->getRedis();
if ($keyName === null) {
$lastKey = $this->_lastKey;
} else {
$lastKey = $this->getKeyName($keyName);
}
return $redis->decrBy($lastKey, $value);
}
/**
* {#inheritdoc}
*
* #return bool
*/
public function flush()
{
}
/**
* Get Prefix
*
* #return string
*/
public function getPrefix()
{
return $this->_prefix;
}
/**
* Get Redis Connection
*
* #return \Redis
*/
public function getRedis()
{
$redis = $this->_redis;
if (!is_object($redis)) {
$this->_connect();
$redis = $this->_redis;
}
return $redis;
}
/**
* Get Key Name
*
* #param $keyName
* #return string
*/
protected function getKeyName($keyName)
{
return $this->_prefix . $keyName;
}
}

Cannot get css/js files to load using custom router

I've been working (mostly for fun) on a custom router.
It's a work in progress, so any advice is always welcome!
But my main problem is that de css/js files are not loaded anymore.
It looks like the path to the files is attached to the current url, so users/(css path).
In Chrome and Firefox the assets just keep loading, no response/code is returned. If I deliberately cause an exception to be thrown, such as altering the file path, I do see the html of the exception being returned.
I've done a lot of debugging already, and cannot seem to figure it out.
/**
* #var
*/
private $routes;
/**
* #var string
* Todo: add this to an ini file or something
*/
private $base_route = "/index.php";
/**
* #param $route
* #param $callback
* #param string $method
*/
public function addRoute($route, $callback, $method = Route::GET)
{
$routes = $this->getRoutes();
if (empty($routes) || !in_array($route, $routes)) {
$this->setRoute(
[
"route" => $route,
"callback" => $callback
], $method
);
return;
}
}
/**
* #param array $route
* #param $method
*/
public function setRoute(array $route, $method)
{
$this->routes[$method][] = $route;
}
/**
* #return mixed
*/
public function getRoutes()
{
return $this->routes;
}
/**
* #throws \Exception
*/
public function handle()
{
$route = $this->getURI();
$route = str_replace($this->base_route, "", $route);
$urlparts = explode("?", $route);
if (count($urlparts) > 1) {
$route = $urlparts[0];
$query = $urlparts[1];
}
if ($this->isAssetRoute($route)) {
$parts = explode("/", $route);
foreach ($parts as $part) {
if ($part !== "public") {
unset($parts[$part]);
} else {
continue;
}
}
$route = implode($parts);
return APP_PATH . "/" . $route;
}
if (empty($route)) {
$this->executeCallback("HomeController");
return;
}
$exists = false;
$routes = $this->getRoutes();
$requested_method = $this->getMethod();
if (!isset($routes[$requested_method])) {
throw new Exception("404: Route {$route} does not exist with method {$requested_method}");
}
$declared_routes = $routes[$requested_method];
$count_routes = count($declared_routes);
for ($i = 0; $i < $count_routes; $i++) {
if ($declared_routes[$i]["route"] === $route) {
$exists = true;
$data = $declared_routes[$i];
continue;
}
}
if (!$exists) {
throw new \Exception("404: route {$route} does not exist!");
}
//Todo: replace [var]
$route = $this->compileRoute($route);
$this->executeCallback($data["callback"]);
}
/**
* #return mixed
*/
private function getProtocol()
{
return $_SERVER["HTTPS"];
}
/**
* #return mixed
*/
public function getMethod()
{
return $_SERVER["REQUEST_METHOD"];
}
/**
* #return mixed
*/
public function getURI()
{
return $_SERVER["REQUEST_URI"];
}
/**
* #param $route
* #param $callback
*/
public function get($route, $callback)
{
$this->setRoute(
[
"route" => $route,
"callback" => $callback
], Route::GET
);
}
/**
* #param $route
* #param $callback
*/
public function post($route, $callback)
{
$this->setRoute(
[
"route" => $route,
"callback" => $callback
], Route::POST
);
}
/**
* #param $route
* #return mixed
*/
public function compileRoute(&$route)
{
$uri = explode("/", $_SERVER["REQUEST_URI"]);
$formatted_route = "";
foreach ($uri as $key => $param) {
$formatted_route .= "/" . preg_replace(
"/\[(.*)\]/", "1", $param
);
}
return str_replace($this->base_route, "", $formatted_route);
}
/**
* #param $callback
* #throws \Exception
*/
public function executeCallback($callback)
{
$callback_data = explode("::", $callback);
$controller = $callback_data[0];
if (!isset($callback_data[1])) {
$method = "index";
} else {
$method = $callback_data[1];
}
if (!class_exists($controller)) {
throw new \Exception("Class {$controller} does not exist!");
}
if (!method_exists($controller, $method)) {
throw new \Exception("Method {$method} does not exist!");
}
$controller::$method();
}
/**
* #param $route
* #return bool
*/
private function isAssetRoute($route)
{
return (stripos($route, "/public/assets/") !== false);
}
Solved it by getting the correct header for it (text/css or application/javascript for those wondering), echoing the file contents and then returning;
I put the code for that in the if ($this->isAssetRoute($route)) statement, located in the handle() method.
All other code in that statement is removed.

Categories