I have an api call that amongst it has Url's that are recalled in it's returned JSON.
I need to find those returned urls that have in them the string used for the original get request and have statuses of 200. I tried using the strpos method, but that didn't seem to work.
public function getCompanyData() {
$client = new Client();
$response = $client->request('GET', 'https://api.github.com/orgs/fakename');
$statusCode = $response->getStatusCode();
$body = $response->getBody()->getContents();
$confirmed = strpos($body,'api.github.com/orgs/fakename');
if($statusCode === 200 && $confirmed !== false) {
return $body;
}
else {
return $statusCode." Error";
}
}
Returned JSON -
{
"login": "fakename",
"id": 1214096,
"node_id": "***=",
"url": "https://api.github.com/orgs/fakename",
"repos_url": "https://api.github.com/orgs/fakename/repos",
"events_url": "https://api.github.com/orgs/fakename/events",
"hooks_url": "https://api.github.com/orgs/fakename/hooks",
"issues_url": "https://api.github.com/orgs/fakename/issues",
"members_url": "https://api.github.com/orgs/fakename/members{/member}",
"public_members_url": "https://api.github.com/orgs/fakename/public_members{/member}",
"avatar_url": "https://avatars3.githubusercontent.com/u/****?v=4",
"description": "",
"name": "fakename",
"company": null,
"blog": "fakename.com",
"location": null,
"email": null,
"twitter_username": null,
"is_verified": false,
"has_organization_projects": true,
"has_repository_projects": true,
"public_repos": 41,
"public_gists": 0,
"followers": 0,
"following": 0,
"html_url": "https://github.com/fakename",
"created_at": "2011-11-22T21:48:43Z",
"updated_at": "2020-09-11T23:05:04Z"
}
One approach would be as follows:
<?php
class SomeClass
{
/**
* #var int The status code of the last http request
*/
private $statusCode;
/**
* Get an array of decoded data from the given url.
* #param $url
* #return array
*/
public function getDataFromUrl($url) {
$client = new Client();
$response = $client->request('GET', $url);
$this->statusCode = $response->getStatusCode();
$body = $response->getBody()->getContents();
return $this->statusCode === 200 ? json_decode($body, true) : [];
}
/**
* Get all data for a given organization including nested ancillary data
* #param string $orgName
* #return array
*/
public function getCompanyData($orgName) {
$mainUrl = "https://api.github.com/orgs/$orgName";
$mainData = $this->getDataFromUrl($mainUrl);
if ($mainData && $this->statusCode === 200) {
$ancillaryUrls = $this->getAncillaryUrlsFromData($mainData, $orgName);
foreach ($ancillaryUrls as $property => $url) {
$ancillaryData = $this->getDataFromUrl($url);
$mainData[$property] = $ancillaryData;
}
}
return $mainData;
}
/**
* Get a JSON string containing all data for a given organization including nested ancillary data
* #param string $orgName
* #return array|mixed
*/
public function getCompanyDataAsJson($orgName) {
return json_encode($this->getCompanyData($orgName));
}
/**
* From the provided array of data, return an new array containing the ancillary urls
* which also need to be requested
* #param array $data
* #param string $orgName
* #return array
*/
public function getAncillaryUrlsFromData($data, $orgName) {
$urls = [];
if (is_array($data)) {
$targetUrl = "api.github.com/orgs/$orgName";
foreach ($data as $property => $value) {
// if property has '_url' and value is like our url, add it to our array of urls
if (strpos($property, '_url') !== false && strpos($value, $targetUrl) !== false) {
$cleanProp = str_replace('_url', '', $property);
$urls[$cleanProp] = $targetUrl;
}
}
}
return $urls;
}
}
Now, if you want the result as an array, you can call:
$someClass = new SomeClass();
$arrayOfData = $someClass->getCompanyData('fakename');
Or, if you want the result as a JSON string, you can call:
$someClass = new SomeClass();
$jsonData = $someClass->getCompanyDataAsJson('fakename');
And the response will have the following keys (in addition to the original main data) "repos", "events", "hooks", "issues", "members", "public_members" all filled with the responses from their individual calls.
Related
Below code is the returned JSON
[{"one":"id","two":"id","three":"id"},{"one":"id","two":"id","three":"id"}]
Below code is the desired result of the returned JSON (without the array bracket)
{"one":"id","two":"id","three":"id"},{"one":"id","two":"id","three":"id"}
Below code is to convert the array to the JSON format
include('connect-db.php');
$result = mysql_query("SELECT * FROM patientvaccinedetail");
$specific = [];
while($row = mysql_fetch_array( $result ,MYSQL_ASSOC)) {
echo "<tr>";
echo '<td width="100px">' . $row['id'] . '</td>';
echo '<td width="200px">' . $row['patientid'] . '</td>';
echo '<td width="200px">' . $row['vaccineid'] . '</td>';
//**********Convert the array into json*******************
$specific[] = ["one" => $row["id"],
"two" => $row["patientid"],
"three" => $row["vaccineid"]];
$result = json_encode($specific,JSON_UNESCAPED_UNICODE);
echo $result;
echo "</tr>";
echo "</table>";
?>
To send the request to the API, iam using Guzzle
And the format the API require is {xx:xx},{xx:xx}
without the square bracket, any idea how to remove it using PHP.
Thanks in advance
$client = new Client([
'headers' => ['Content-Type' => 'application/json',
'Token' => $token]
]);
$response = $client->post('http://localhost:91/Religious',
['body' => ***Where the json will be place***]
);
I read a nice solution in the comments of the first post by deceze ♦ with trim().
$yourJson = trim($yourJson, '[]');
You can also use regular expression:
// if nothing is found, your json has already no brackets or is invalid.
if (preg_match('/^\[(.+)\]$/', $yourJson, $new))
{
/**
* $new[0] = $yourJson
* $new[1] = what's in the parenthesis
*/
$yourJson = $new[1];
}
Or, you may use substr():
$yourJson = substr($yourJson, 1, strlen($yourJson) - 2);
EDIT:
When it says in the request body format : application/json, I do not think that you have to remove the brackets. Did you even try with them?
You are trying to convert a PHP array to a JSON array, so php wrap the result in brackets, it's totally normal. If you need a JSON object Then I would suggest to use JSON_FORCE_OBJECT as additional option(parameters) in json_encode.
$object = json_encode($array, JSON_FORCE_OBJECT);
Try this
str_replace(array('[', ']'), '', htmlspecialchars(json_encode($result), ENT_NOQUOTES));
You might need to use the implode function after a json decode. for example:
implode(',',json_decode($text_from_db or $array))
for example $text_from_db=["rice","beans"]
the result will be- rice,beans
you can trimit see example below
trim($data, '[]')
I've added comments as to what the OP is trying to do. But here's my solution for future visitors of this question.
class Thing implements \JsonSerializable
{
private $name;
private $description;
private $code;
/**
* Get the value of name
*/
public function getName()
{
return $this->name;
}
/**
* Set the value of name
*
* #return self
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get the value of description
*/
public function getDescription()
{
return $this->description;
}
/**
* Set the value of description
*
* #return self
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get the value of code
*/
public function getCode()
{
return $this->code;
}
/**
* Set the value of code
*
* #return self
*/
public function setCode($code)
{
$this->code = $code;
return $this;
}
public function jsonSerialize()
{
$vars = get_object_vars($this);
return $vars;
}
}
$thing = new Thing();
$thing->setName('Name');
$thing->setDescription('Description');
$thing->setCode('Code');
$results['items'] = [
'thing1' => $thing,
'thing2' => $thing
];
echo json_encode($results);
Here's the output
{
"items": {
"thing1": {
"name": "Name",
"description": "Description",
"code": "Code"
},
"thing2": {
"name": "Name",
"description": "Description",
"code": "Code"
}
}
}
This will remove the outer wrapper without disturbing any inner wrappers:
$wrapped = <<<EOD
[{"one":"id","two":"id","three":"id"},{"one":"id","two":"id","three":"id"}]
EOD;
$array = json_decode($wrapped, true);
$unwrapped = json_encode($array, JSON_FORCE_OBJECT);
print_r($unwrapped);
// {"0":{"one":"id","two":"id","three":"id"},"1":{"one":"id","two":"id","three":"id"}}
My suggestion is to use JSON string and perform String operations to remove all those not required characters.
Reason for doing this, the required output is not a valid JSON and won't be accepted by API. As you need it however, I would suggest you to convert the array into json using json_encode and then perform string operations to convert it into your desired output.
This question already has answers here:
PHP parse/syntax errors; and how to solve them
(20 answers)
Closed 5 years ago.
public function is used inside a class called Client but it still throws error like this for every function in that class. Any solution to this? I am trying to test getstream for php. I am getting this error in client.php
I know this error occurs when class isn't declared while using public function but in this case the class has been declared and according to the documentation this should have worked without an error.
<?php
namespace GuzzleHttp;
use GuzzleHttp\Cookie\CookieJar;
use GuzzleHttp\Promise;
use GuzzleHttp\Psr7;
use Psr\Http\Message\UriInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
/**
* #method ResponseInterface get(string|UriInterface $uri, array $options = [])
* #method ResponseInterface head(string|UriInterface $uri, array $options = [])
* #method ResponseInterface put(string|UriInterface $uri, array $options = [])
* #method ResponseInterface post(string|UriInterface $uri, array $options = [])
* #method ResponseInterface patch(string|UriInterface $uri, array $options = [])
* #method ResponseInterface delete(string|UriInterface $uri, array $options = [])
* #method Promise\PromiseInterface getAsync(string|UriInterface $uri, array $options = [])
* #method Promise\PromiseInterface headAsync(string|UriInterface $uri, array $options = [])
* #method Promise\PromiseInterface putAsync(string|UriInterface $uri, array $options = [])
* #method Promise\PromiseInterface postAsync(string|UriInterface $uri, array $options = [])
* #method Promise\PromiseInterface patchAsync(string|UriInterface $uri, array $options = [])
* #method Promise\PromiseInterface deleteAsync(string|UriInterface $uri, array $options = [])
*/
class Client implements ClientInterface
{
/** #var array Default request options */
private $config;
/**
* Clients accept an array of constructor parameters.
*
* Here's an example of creating a client using a base_uri and an array of
* default request options to apply to each request:
*
* $client = new Client([
* 'base_uri' => 'http://www.foo.com/1.0/',
* 'timeout' => 0,
* 'allow_redirects' => false,
* 'proxy' => '192.168.16.1:10'
* ]);
*
* Client configuration settings include the following options:
*
* - handler: (callable) Function that transfers HTTP requests over the
* wire. The function is called with a Psr7\Http\Message\RequestInterface
* and array of transfer options, and must return a
* GuzzleHttp\Promise\PromiseInterface that is fulfilled with a
* Psr7\Http\Message\ResponseInterface on success. "handler" is a
* constructor only option that cannot be overridden in per/request
* options. If no handler is provided, a default handler will be created
* that enables all of the request options below by attaching all of the
* default middleware to the handler.
* - base_uri: (string|UriInterface) Base URI of the client that is merged
* into relative URIs. Can be a string or instance of UriInterface.
* - **: any request option
*
* #param array $config Client configuration settings.
*
* #see \GuzzleHttp\RequestOptions for a list of available request options.
*/
//public function __construct(array $config = [])
public function __construct(array $config = ['verify' => false]) {
{
if (!isset($config['handler'])) {
$config['handler'] = HandlerStack::create();
}
// Convert the base_uri to a UriInterface
if (isset($config['base_uri'])) {
$config['base_uri'] = Psr7\uri_for($config['base_uri']);
}
$this->configureDefaults($config);
}
public function __call($method, $args)
{
if (count($args) < 1) {
throw new \InvalidArgumentException('Magic request methods require a URI and optional options array');
}
$uri = $args[0];
$opts = isset($args[1]) ? $args[1] : [];
return substr($method, -5) === 'Async'
? $this->requestAsync(substr($method, 0, -5), $uri, $opts)
: $this->request($method, $uri, $opts);
}
public function sendAsync(RequestInterface $request, array $options = [])
{
// Merge the base URI into the request URI if needed.
$options = $this->prepareDefaults($options);
return $this->transfer(
$request->withUri($this->buildUri($request->getUri(), $options), $request->hasHeader('Host')),
$options
);
}
public function send(RequestInterface $request, array $options = [])
{
$options[RequestOptions::SYNCHRONOUS] = true;
return $this->sendAsync($request, $options)->wait();
}
public function requestAsync($method, $uri = '', array $options = [])
{
$options = $this->prepareDefaults($options);
// Remove request modifying parameter because it can be done up-front.
$headers = isset($options['headers']) ? $options['headers'] : [];
$body = isset($options['body']) ? $options['body'] : null;
$version = isset($options['version']) ? $options['version'] : '1.1';
// Merge the URI into the base URI.
$uri = $this->buildUri($uri, $options);
if (is_array($body)) {
$this->invalidBody();
}
$request = new Psr7\Request($method, $uri, $headers, $body, $version);
// Remove the option so that they are not doubly-applied.
unset($options['headers'], $options['body'], $options['version']);
return $this->transfer($request, $options);
}
public function request($method, $uri = '', array $options = [])
{
$options[RequestOptions::SYNCHRONOUS] = true;
return $this->requestAsync($method, $uri, $options)->wait();
}
public function getConfig($option = null)
{
return $option === null
? $this->config
: (isset($this->config[$option]) ? $this->config[$option] : null);
}
private function buildUri($uri, array $config)
{
// for BC we accept null which would otherwise fail in uri_for
$uri = Psr7\uri_for($uri === null ? '' : $uri);
if (isset($config['base_uri'])) {
$uri = Psr7\UriResolver::resolve(Psr7\uri_for($config['base_uri']), $uri);
}
return $uri->getScheme() === '' && $uri->getHost() !== '' ? $uri->withScheme('http') : $uri;
}
/**
* Configures the default options for a client.
*
* #param array $config
*/
private function configureDefaults(array $config)
{
$defaults = [
'allow_redirects' => RedirectMiddleware::$defaultSettings,
'http_errors' => true,
'decode_content' => true,
'verify' => true,
'cookies' => false
];
// Use the standard Linux HTTP_PROXY and HTTPS_PROXY if set.
// We can only trust the HTTP_PROXY environment variable in a CLI
// process due to the fact that PHP has no reliable mechanism to
// get environment variables that start with "HTTP_".
if (php_sapi_name() == 'cli' && getenv('HTTP_PROXY')) {
$defaults['proxy']['http'] = getenv('HTTP_PROXY');
}
if ($proxy = getenv('HTTPS_PROXY')) {
$defaults['proxy']['https'] = $proxy;
}
if ($noProxy = getenv('NO_PROXY')) {
$cleanedNoProxy = str_replace(' ', '', $noProxy);
$defaults['proxy']['no'] = explode(',', $cleanedNoProxy);
}
$this->config = $config + $defaults;
if (!empty($config['cookies']) && $config['cookies'] === true) {
$this->config['cookies'] = new CookieJar();
}
// Add the default user-agent header.
if (!isset($this->config['headers'])) {
$this->config['headers'] = ['User-Agent' => default_user_agent()];
} else {
// Add the User-Agent header if one was not already set.
foreach (array_keys($this->config['headers']) as $name) {
if (strtolower($name) === 'user-agent') {
return;
}
}
$this->config['headers']['User-Agent'] = default_user_agent();
}
}
/**
* Merges default options into the array.
*
* #param array $options Options to modify by reference
*
* #return array
*/
private function prepareDefaults($options)
{
$defaults = $this->config;
if (!empty($defaults['headers'])) {
// Default headers are only added if they are not present.
$defaults['_conditional'] = $defaults['headers'];
unset($defaults['headers']);
}
// Special handling for headers is required as they are added as
// conditional headers and as headers passed to a request ctor.
if (array_key_exists('headers', $options)) {
// Allows default headers to be unset.
if ($options['headers'] === null) {
$defaults['_conditional'] = null;
unset($options['headers']);
} elseif (!is_array($options['headers'])) {
throw new \InvalidArgumentException('headers must be an array');
}
}
// Shallow merge defaults underneath options.
$result = $options + $defaults;
// Remove null values.
foreach ($result as $k => $v) {
if ($v === null) {
unset($result[$k]);
}
}
return $result;
}
/**
* Transfers the given request and applies request options.
*
* The URI of the request is not modified and the request options are used
* as-is without merging in default options.
*
* #param RequestInterface $request
* #param array $options
*
* #return Promise\PromiseInterface
*/
private function transfer(RequestInterface $request, array $options)
{
// save_to -> sink
if (isset($options['save_to'])) {
$options['sink'] = $options['save_to'];
unset($options['save_to']);
}
// exceptions -> http_errors
if (isset($options['exceptions'])) {
$options['http_errors'] = $options['exceptions'];
unset($options['exceptions']);
}
$request = $this->applyOptions($request, $options);
$handler = $options['handler'];
try {
return Promise\promise_for($handler($request, $options));
} catch (\Exception $e) {
return Promise\rejection_for($e);
}
}
/**
* Applies the array of request options to a request.
*
* #param RequestInterface $request
* #param array $options
*
* #return RequestInterface
*/
private function applyOptions(RequestInterface $request, array &$options)
{
$modify = [];
if (isset($options['form_params'])) {
if (isset($options['multipart'])) {
throw new \InvalidArgumentException('You cannot use '
. 'form_params and multipart at the same time. Use the '
. 'form_params option if you want to send application/'
. 'x-www-form-urlencoded requests, and the multipart '
. 'option to send multipart/form-data requests.');
}
$options['body'] = http_build_query($options['form_params'], '', '&');
unset($options['form_params']);
$options['_conditional']['Content-Type'] = 'application/x-www-form-urlencoded';
}
if (isset($options['multipart'])) {
$options['body'] = new Psr7\MultipartStream($options['multipart']);
unset($options['multipart']);
}
if (isset($options['json'])) {
$options['body'] = \GuzzleHttp\json_encode($options['json']);
unset($options['json']);
$options['_conditional']['Content-Type'] = 'application/json';
}
if (!empty($options['decode_content'])
&& $options['decode_content'] !== true
) {
$modify['set_headers']['Accept-Encoding'] = $options['decode_content'];
}
if (isset($options['headers'])) {
if (isset($modify['set_headers'])) {
$modify['set_headers'] = $options['headers'] + $modify['set_headers'];
} else {
$modify['set_headers'] = $options['headers'];
}
unset($options['headers']);
}
if (isset($options['body'])) {
if (is_array($options['body'])) {
$this->invalidBody();
}
$modify['body'] = Psr7\stream_for($options['body']);
unset($options['body']);
}
if (!empty($options['auth']) && is_array($options['auth'])) {
$value = $options['auth'];
$type = isset($value[2]) ? strtolower($value[2]) : 'basic';
switch ($type) {
case 'basic':
$modify['set_headers']['Authorization'] = 'Basic '
. base64_encode("$value[0]:$value[1]");
break;
case 'digest':
// #todo: Do not rely on curl
$options['curl'][CURLOPT_HTTPAUTH] = CURLAUTH_DIGEST;
$options['curl'][CURLOPT_USERPWD] = "$value[0]:$value[1]";
break;
}
}
if (isset($options['query'])) {
$value = $options['query'];
if (is_array($value)) {
$value = http_build_query($value, null, '&', PHP_QUERY_RFC3986);
}
if (!is_string($value)) {
throw new \InvalidArgumentException('query must be a string or array');
}
$modify['query'] = $value;
unset($options['query']);
}
// Ensure that sink is not an invalid value.
if (isset($options['sink'])) {
// TODO: Add more sink validation?
if (is_bool($options['sink'])) {
throw new \InvalidArgumentException('sink must not be a boolean');
}
}
$request = Psr7\modify_request($request, $modify);
if ($request->getBody() instanceof Psr7\MultipartStream) {
// Use a multipart/form-data POST if a Content-Type is not set.
$options['_conditional']['Content-Type'] = 'multipart/form-data; boundary='
. $request->getBody()->getBoundary();
}
// Merge in conditional headers if they are not present.
if (isset($options['_conditional'])) {
// Build up the changes so it's in a single clone of the message.
$modify = [];
foreach ($options['_conditional'] as $k => $v) {
if (!$request->hasHeader($k)) {
$modify['set_headers'][$k] = $v;
}
}
$request = Psr7\modify_request($request, $modify);
// Don't pass this internal value along to middleware/handlers.
unset($options['_conditional']);
}
return $request;
}
private function invalidBody()
{
throw new \InvalidArgumentException('Passing in the "body" request '
. 'option as an array to send a POST request has been deprecated. '
. 'Please use the "form_params" request option to send a '
. 'application/x-www-form-urlencoded request, or a the "multipart" '
. 'request option to send a multipart/form-data request.');
}
}
public function __construct(array $config = ['verify' => false]) {
{ // <-- duplicated brace here
Can i get the effect of JSON_NUMERIC_CHECK without JSON?
i.e. Recrusive replacement of numeric strings to ints or floats.
Example with JSON_NUMERIC_CHECK:
<?php
// some input from somewhre
$data = explode(',', 'abc,7,3.14');
echo "Before:"; var_dump($data);
$data = json_decode(json_encode($data, JSON_NUMERIC_CHECK), TRUE);
echo "After:"; var_dump($data);
But I geuss converting to json and back is slow, is there some other way to get the same result?
You can loop over your strings and cast any numeric value to int or float using the following code:
/**
* Normalize an object, array or string by casting all
* numeric strings it contains to numeric values.
*
* #param array|object|string $data
* #return mixed
*/
function normalize($data) {
if (is_array($data))
return array_map('normalize', $data);
if (is_object($data))
return (object) normalize(get_object_vars($data));
return is_numeric($data) ? $data + 0 : $data;
}
$data = "15,2.35,foo";
$data = normalize(explode(',', $data));
// => [15, 2.35, 'foo']
Hope this helps :)
More efficient way
/**
* Normalize an string or object by casting all
* numeric strings it contains to numeric values.
* Note that it changes the variable directly
* instead of returning a copy.
*
* #param object|string $data
* #return void
*/
function normalizeItem(&$data) {
if (is_object($data)) {
$data = get_object_vars($data);
normalize($data);
$data = (object) $data;
} else {
$data = is_numeric($data) ? $data + 0 : $data;
}
}
/**
* Applies normalizeItem to an array recursively.
*
* #param array &$list
* #return bool
*/
function normalize(&$list) {
return array_walk_recursive($list, 'normalizeItem');
}
You can use array_map() with a callback.
$data = explode(',', 'abc,7,3.14');
$re = array_map(function(&$a) {
return ctype_digit($a) ? intval($a) : $a;
}, $data);
var_dump($re);
https://eval.in/715641
I’m trying to calculate a signature to make Amazon Marketplace API calls, but I keep getting the following error:
The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.
I’ve wrapped the signature creation process into a class:
<?php
namespace App\Marketplace\Amazon;
class Signature
{
protected $signedString;
public function __construct($url, array $parameters, $secretAccessKey)
{
$stringToSign = $this->calculateStringToSign($url, $parameters);
$this->signedString = $this->sign($stringToSign, $secretAccessKey);
}
protected function calculateStringToSign($url, array $parameters)
{
$url = parse_url($url);
$string = "POST\n";
$string .= $url['host'] . "\n";
$string .= $url['path'] . "\n";
$string .= $this->getParametersAsString($parameters);
return $string;
}
protected function sign($data, $secretAccessKey)
{
return base64_encode(hash_hmac('sha256', $data, $secretAccessKey, true));
}
protected function getParametersAsString(array $parameters)
{
uksort($parameters, 'strcmp');
$queryParameters = [];
foreach ($parameters as $key => $value) {
$queryParameters[$key] = $this->urlEncode($value);
}
return http_build_query($queryParameters);
}
protected function urlEncode($value)
{
return str_replace('%7E', '~', rawurlencode($value));
}
public function __toString()
{
return $this->signedString;
}
}
But I can’t for the life of me see where I’m going wrong. I’ve followed the guide in the API, and looked at the Java example as well as the antiquated Marketplace PHP SDK*.
EDIT: And here is how I’m using the Signature class:
$version = '2011-07-01';
$url = 'https://mws.amazonservices.com/Sellers/'.$version;
$timestamp = gmdate('c', time());
$parameters = [
'AWSAccessKeyId' => $command->accessKeyId,
'Action' => 'GetAuthToken',
'SellerId' => $command->sellerId,
'SignatureMethod' => 'HmacSHA256',
'SignatureVersion' => 2,
'Timestamp' => $timestamp,
'Version' => $version,
];
$signature = new Signature($url, $parameters, $command->secretAccessKey);
$parameters['Signature'] = strval($signature);
try {
$response = $this->client->post($url, [
'headers' => [
'User-Agent' => 'my-app-name',
],
'body' => $parameters,
]);
dd($response->getBody());
} catch (\Exception $e) {
dd(strval($e->getResponse()));
}
As an aside: I know the Marketplace credentials are correct as I’ve logged in to the account and retrieved the access key, secret, and seller IDs.
* I’m not using the SDK as it doesn’t support the API call I need: SubmitFeed.
I’m not sure what I’ve changed, but my signature generation is working now. Below is the contents of the class:
<?php
namespace App\Marketplace\Amazon;
class Signature
{
/**
* The signed string.
*
* #var string
*/
protected $signedString;
/**
* Create a new signature instance.
*
* #param string $url
* #param array $data
* #param string $secretAccessKey
*/
public function __construct($url, array $parameters, $secretAccessKey)
{
$stringToSign = $this->calculateStringToSign($url, $parameters);
$this->signedString = $this->sign($stringToSign, $secretAccessKey);
}
/**
* Calculate the string to sign.
*
* #param string $url
* #param array $parameters
* #return string
*/
protected function calculateStringToSign($url, array $parameters)
{
$url = parse_url($url);
$string = "POST\n";
$string .= $url['host']."\n";
$string .= $url['path']."\n";
$string .= $this->getParametersAsString($parameters);
return $string;
}
/**
* Computes RFC 2104-compliant HMAC signature.
*
* #param string $data
* #param string $secretAccessKey
* #return string
*/
protected function sign($data, $secretAccessKey)
{
return base64_encode(hash_hmac('sha256', $data, $secretAccessKey, true));
}
/**
* Convert paremeters to URL-encoded query string.
*
* #param array $parameters
* #return string
*/
protected function getParametersAsString(array $parameters)
{
uksort($parameters, 'strcmp');
$queryParameters = [];
foreach ($parameters as $key => $value) {
$key = rawurlencode($key);
$value = rawurlencode($value);
$queryParameters[] = sprintf('%s=%s', $key, $value);
}
return implode('&', $queryParameters);
}
/**
* The string representation of this signature.
*
* #return string
*/
public function __toString()
{
return $this->signedString;
}
}
Try this function after calling your sign function:
function amazonEncode($text)
{
$encodedText = "";
$j = strlen($text);
for($i=0;$i<$j;$i++)
{
$c = substr($text,$i,1);
if (!preg_match("/[A-Za-z0-9\-_.~]/",$c))
{
$encodedText .= sprintf("%%%02X",ord($c));
}
else
{
$encodedText .= $c;
}
}
return $encodedText;
}
Reference
After you've created the canonical string as described in Format the
Query Request, you calculate the signature by creating a hash-based
message authentication code (HMAC) using either the HMAC-SHA1 or
HMAC-SHA256 protocols. The HMAC-SHA256 protocol is preferred.
The resulting signature must be base-64 encoded and then URI encoded.
I have a page on my web server that is PHP that is set to do this
if ($_POST['post'] == true) {
echo: 'hello, world';
}
I want to create a page that calls to that page, posts "post" equal to "true" and then returns the value "hello, world". I have a script that works, but only if the pages are on different servers. Unfortunately, both of these pages are on the same server, so, heres my code, and I'm hoping you guys can help me, Thank you :)
function post($site, $post) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$site);
curl_setopt($ch, CURLOPT_FAILONERROR,1);
curl_setopt ($ch, CURLOPT_POST, 1);
curl_setopt ($ch, CURLOPT_POSTFIELDS, $post);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION,1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch, CURLOPT_TIMEOUT, 15);
$retValue = curl_exec($ch);
curl_close($ch);
return $retValue;
}
echo post('data.php', 'post=true');
class Curl_lib
{
private $resource = NULL; // libcurb init() resource
private $config = array(); // Construction config
public $header = array(); // Response Header
public $body = array(); // Response Body
/**
* Factory Method
*/
public static function factory($data = array())
{
return new self($data);
}
/**
* Constructor
*/
public function __construct($data = array())
{
$config = array(
CURLOPT_HEADER => false
);
// Apply any passed configuration
$data += $config;
$this->config = $data;
$this->resource = curl_init();
// Apply configuration settings
foreach ($this->config as $key => $value)
{
$this->set_opt($key, $value);
}
}
/**
* Set option
*
* #param String Curl option to set
* #param String Value for option
* #chainable
*/
public function set_opt($key, $value)
{
curl_setopt($this->resource, $key, $value);
return $this;
}
/**
* Execute the curl request and return the response
*
* #return String Returned output from the requested resource
* #throws Kohana_User_Exception
*/
public function exec()
{
$ret = curl_exec($this->resource);
//Wrap the error reporting in an exception
if ($ret === false)
{
kohana::log('error', curl_error($this->resource));
throw new Exception(curl_error($this->resource));
}
else
{
return $ret;
}
}
/**
* Get Error
* Returns any current error for the curl request
*
* #return string The error
*/
public function get_error()
{
return curl_error($this->resource);
}
/**
* Destructor
*/
function __destruct()
{
curl_close($this->resource);
}
/**
* Get
* Execute an HTTP GET request using curl
*
* #param String url to request
* #param Array additional headers to send in the request
* #param Bool flag to return only the headers
* #param Array Additional curl options to instantiate curl with
* #return Array array of 'header' and 'body'
*/
public static function get($url,
Array $headers = array(),
$headers_only = FALSE,
Array $curl_options = array())
{
$ch = self::factory($curl_options);
$ch->set_opt(CURLOPT_URL, $url)
->set_opt(CURLOPT_RETURNTRANSFER, TRUE)
->set_opt(CURLOPT_NOBODY, $headers_only)
->set_opt(CURLOPT_HTTPHEADER, array("Expect:"))
->set_opt(CURLOPT_HEADERFUNCTION, array($ch, 'read_header'))
->set_opt(CURLOPT_WRITEFUNCTION, array($ch, 'read_body'));
//Set any additional headers
if(!empty($headers)) $ch->set_opt(CURLOPT_HTTPHEADER, $headers);
$ch->exec();
return array(
'header' => $ch->header,
'body' => $ch->body
);
}
/**
* Post
* Execute an HTTP POST request, posting the past parameters
*
* #param String url to request
* #param Array past data to post to $url
* #param Array additional headers to send in the request
* #param Bool flag to return only the headers
* #param Array Additional curl options to instantiate curl with
* #return Array array of 'header' and 'body'
*/
public static function post($url,
Array $data = array(),
Array $headers = array(),
$headers_only = FALSE,
Array $curl_options = array())
{
$ch = self::factory($curl_options);
$ch->set_opt(CURLOPT_URL, $url)
->set_opt(CURLOPT_NOBODY, $headers_only)
->set_opt(CURLOPT_RETURNTRANSFER, TRUE)
->set_opt(CURLOPT_POST, TRUE)
->set_opt(CURLOPT_POSTFIELDS, $data)
->set_opt(CURLOPT_HTTPHEADER, array("Expect:"))
->set_opt(CURLOPT_HEADERFUNCTION, array($ch, 'read_header'))
->set_opt(CURLOPT_WRITEFUNCTION, array($ch, 'read_body'));
//Set any additional headers
if(!empty($headers)) $ch->set_opt(CURLOPT_HTTPHEADER, $headers);
$ch->exec();
return array(
'header' => $ch->header,
'body' => $ch->body
);
}
/**
* Read Header
* A private method to be used by libcurl when reading header.
*
* #param String Curl Binded Resource
* #param String Header String
* #return Integer Header String Length
*/
private function read_header($ch, $string)
{
$length = strlen($string);
// Trim Header String
$string = trim($string);
// If not empty, push into header array
if (!empty($string))
{
array_push($this->header, $string);
}
return $length;
}
/**
* Read Body
* A private method to be used by libcurl when reading body content.
*
* #param String Curl Binded Resource
* #param String Body String
* #return Integer Body String Length
*/
private function read_body($ch, $string)
{
$length = strlen($string);
// If not empty, push into body array
if (!empty($string))
{
array_push($this->body, $string);
}
return $length;
}
}
With the class above,
what you need to do is just:
$response = Curl_lib::post('http://localhost/example.php', $post);
The $post as HTTP POST params and values to be posted to http://localhost/example.php'.
It can be $_POST too, as long as an associative array will do.
The response is in the format of:
$response = array(
'header' => array(),
'body' => array(),
);
you can always use var_dump with xdebug to have a great view. print_r will is great too.
Hope this help :)
Since you have control over both pages, why not change your conditional? (adding the whole $_POST in this example incase there are more conditionals)
if( empty($postData) ) {
$postData = $_POST;
}
if ( $postData['post'] == true) { echo: 'hello, world'; }
Then, you can just set the var and include the file:
$postData = array('post' => true);
include ( 'data.php' );
CURL doesn't support relative URL, you need to do something like,
echo post('http://localhost/data.php', 'post=true');
You can also just include the page like this,
<?php
$_POST['post'] = true;
include 'data.php';
?>