Issues calculating signature for Amazon Marketplace API - php

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.

Related

How to get uuid(dynamic value) in FeatureContext method

My code access only hard coded ID (/api/user/{id}). But I want it works with dynamic value (for example: uuid).
/**
* #When I send a :http request to :url
*
* #param $http
* #param $url
*/
public function iSendARequestTo($http, $url)
{
$url = $this->attachQueries($url);
if ($this->isUrlContainsRuntimeParameters($url)) {
$url = $this->mergeRuntimeParametersValues($url);
}
$this->client->request(
$http,
$url,
$this->parameters,
[],
$this->headers,
$this->rawData
);
$this->response = $this->client->getResponse();
}
Extra Functions:
private function attachQueries($url)
{
foreach ($this->queries as $key => $value) {
if(strpos($url,'?') !== false) {
$url .= '&' .$key. '=' .$value;
} else {
$url .= '?' .$key. '=' .$value;
}
}
return $url;
}
private function isUrlContainsRuntimeParameters($url)
{
preg_match(self::RUNTIME_PARAMETER_PATTERN, $url, $matches);
return !empty($matches);
}
private function mergeRuntimeParametersValues($parameter)
{
preg_match(self::RUNTIME_PARAMETER_PATTERN, $parameter, $matches);
return empty($matches)
? $parameter
: preg_replace(self::RUNTIME_PARAMETER_PATTERN, $this->runtimeParameters[$matches[1]], $parameter);
}
I want to rebuild method "iSendARequestTo()" make it works with dynamic Doctrine Values (e.g. uuid)

How to remove the Square Bracket in JSON using PHP

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.

Parse error: syntax error, unexpected 'public' (T_PUBLIC) [duplicate]

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

Error: "__construct() must be an array, none given"

With the following code in my controller, I was able to pass my OAuth access tokens into J7mbo's TwitterAPIExchange and perform a query on the Twitter API version 1.1:
// Set access tokens here
$settings = array(
'oauth_access_token' => "My Oauth Access Token",
'oauth_access_token_secret' => "My Oauth Access Token Secret",
'consumer_key' => "My Consumer Key",
'consumer_secret' => "My Consumer Secret"
);
$url = 'https://api.twitter.com/1.1/followers/ids.json';
$getfield = '?username=somename';
$requestMethod = 'GET';
$twitter = new TwitterAPIExchange($settings);
echo $twitter->setGetfield($getfield)
->buildOauth($url, $requestMethod)
->performRequest();
However, for security reasons, I read that the consumer secret should not be human readeable within the app. So I moved my OAuth access tokens away from my controller (see above) to the following location (see below):
application\config\twitter_settings.php
<?php if( ! defined('BASEPATH'))exit('No direct script access allowed');
// Set access tokens here
$config['oauth_access_token'] = "My access token";
$config['oauth_access_token_secret'] = "My access secret";
$config['consumer_key'] = "My consumer key";
$config['consumer_secret'] = "My ENCRYPTED consumer_secret";
/* End of file Settings.php */
and attempted to load my access tokens from my controller
$this->config->load('twitter_settings');
$this->load->library('/twitter/TwitterAPIExchange');
Now I'm getting the following error and I'm not sure how to pass my OAuth access tokens to J7mbo's TwitterAPIExchange:
A PHP Error was encountered
Severity: 4096
Message: Argument 1 passed to TwitterAPIExchange::__construct() must
be an array, none given, called in
C:\wamp\www\twitter_app\theworks\core\Loader.php on line 1099 and
defined
Filename: twitter/TwitterAPIExchange.php
Line Number: 33
Make sure you are passing in the correct parameters
Here is my controller:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class Search extends CI_Controller {
public function index()
{
$this->config->load('twitter_settings');
//$this->load->library('encrypt');
$this->load->library('/twitter/TwitterAPIExchange');
$url = 'https://api.twitter.com/1.1/followers/ids.json';
$getfield = '?username=stackexchange';
$requestMethod = 'GET';
$twitter = new TwitterAPIExchange(/* I need to pass the OAuth tokens here */);
echo $twitter->setGetfield($getfield)
->buildOauth($url, $requestMethod)
->performRequest();
}
}
/* End of file search.php */
/* Location: ./application/controllers/search.php */
and here is J7mbo's TwitterAPIExchange code:
<?php
/**
* Twitter-API-PHP : Simple PHP wrapper for the v1.1 API
*
* PHP version 5.3.10
*
* #category Awesomeness
* #package Twitter-API-PHP
* #author James Mallison <me#j7mbo.co.uk>
* #license http://opensource.org/licenses/gpl-license.php GNU Public License
* #link http://github.com/j7mbo/twitter-api-php
*/
class TwitterAPIExchange
{
private $oauth_access_token;
private $oauth_access_token_secret;
private $consumer_key;
private $consumer_secret;
private $postfields;
private $getfield;
protected $oauth;
public $url;
/**
* Create the API access object. Requires an array of settings::
* oauth access token, oauth access token secret, consumer key, consumer secret
* These are all available by creating your own application on dev.twitter.com
* Requires the cURL library
*
* #param array $settings
*/
public function __construct(array $settings)
{
if (!in_array('curl', get_loaded_extensions()))
{
exit('You need to install cURL, see: http://curl.haxx.se/docs/install.html');
}
if (!isset($settings['oauth_access_token'])
|| !isset($settings['oauth_access_token_secret'])
|| !isset($settings['consumer_key'])
|| !isset($settings['consumer_secret']))
{
exit('Make sure you are passing in the correct parameters');
}
$this->oauth_access_token = $settings['oauth_access_token'];
$this->oauth_access_token_secret = $settings['oauth_access_token_secret'];
$this->consumer_key = $settings['consumer_key'];
$this->consumer_secret = $settings['consumer_secret'];
}
/**
* Set postfields array, example: array('screen_name' => 'J7mbo')
*
* #param array $array Array of parameters to send to API
* #return \TwitterAPIExchange Instance of self for method chaining
*/
public function setPostfields(array $array)
{
if (!is_null($this->getGetfield()))
{
exit('You can only choose get OR post fields.');
}
$this->postfields = $array;
return $this;
}
/**
* Set getfield string, example: '?screen_name=J7mbo'
*
* #param string $string Get key and value pairs as string
* #return \TwitterAPIExchange Instance of self for method chaining
*/
public function setGetfield($string)
{
if (!is_null($this->getPostfields()))
{
exit('You can only choose get OR post fields.');
}
$this->getfield = $string;
return $this;
}
/**
* Get getfield string (simple getter)
*
* #return string $this->getfields
*/
public function getGetfield()
{
return $this->getfield;
}
/**
* Get postfields array (simple getter)
*
* #return array $this->postfields
*/
public function getPostfields()
{
return $this->postfields;
}
/**
* Build the Oauth object using params set in construct and additionals
* passed to this method. For v1.1, see: https://dev.twitter.com/docs/api/1.1
*
* #param string $url The API url to use. Example: https://api.twitter.com/1.1/search/tweets.json
* #param string $requestMethod Either POST or GET
* #return \TwitterAPIExchange Instance of self for method chaining
*/
public function buildOauth($url, $requestMethod)
{
if (strtolower($requestMethod) !== 'post' && strtolower($requestMethod) !== 'get')
{
exit('Request method must be either POST or GET');
}
$consumer_key = $this->consumer_key;
$consumer_secret = $this->consumer_secret;
$oauth_access_token = $this->oauth_access_token;
$oauth_access_token_secret = $this->oauth_access_token_secret;
$oauth = array(
'oauth_consumer_key' => $consumer_key,
'oauth_nonce' => time(),
'oauth_signature_method' => 'HMAC-SHA1',
'oauth_token' => $oauth_access_token,
'oauth_timestamp' => time(),
'oauth_version' => '1.0'
);
$getfield = $this->getGetfield();
if (!is_null($getfield))
{
$getfields = str_replace('?', '', explode('&', $getfield));
foreach ($getfields as $g)
{
$split = explode('=', $g);
$oauth[$split[0]] = $split[1];
}
}
$base_info = $this->buildBaseString($url, $requestMethod, $oauth);
$composite_key = rawurlencode($consumer_secret) . '&' . rawurlencode($oauth_access_token_secret);
$oauth_signature = base64_encode(hash_hmac('sha1', $base_info, $composite_key, true));
$oauth['oauth_signature'] = $oauth_signature;
$this->url = $url;
$this->oauth = $oauth;
return $this;
}
/**
* Perform the acual data retrieval from the API
*
* #param boolean optional $return If true, returns data.
* #return json If $return param is true, returns json data.
*/
public function performRequest($return = true)
{
if (!is_bool($return))
{
exit('performRequest parameter must be true or false');
}
$header = array($this->buildAuthorizationHeader($this->oauth), 'Expect:');
$getfield = $this->getGetfield();
$postfields = $this->getPostfields();
$options = array(
CURLOPT_HTTPHEADER => $header,
CURLOPT_HEADER => false,
CURLOPT_URL => $this->url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYPEER => false
);
if (!is_null($postfields))
{
$options[CURLOPT_POSTFIELDS] = $postfields;
}
else
{
if ($getfield !== '')
{
$options[CURLOPT_URL] .= $getfield;
}
}
$feed = curl_init();
curl_setopt_array($feed, $options);
$json = curl_exec($feed);
curl_close($feed);
if ($return) { return $json; }
}
/**
* Private method to generate the base string used by cURL
*
* #param string $baseURI
* #param string $method
* #param string $params
* #return string Built base string
*/
private function buildBaseString($baseURI, $method, $params)
{
$return = array();
ksort($params);
foreach($params as $key=>$value)
{
$return[] = "$key=" . $value;
}
return $method . "&" . rawurlencode($baseURI) . '&' . rawurlencode(implode('&', $return));
}
/**
* Private method to generate authorization header used by cURL
*
* #param array $oauth Array of oauth data generated by buildOauth()
* #return string $return Header used by cURL for request
*/
private function buildAuthorizationHeader($oauth)
{
$return = 'Authorization: OAuth ';
$values = array();
foreach($oauth as $key => $value)
{
$values[] = "$key=\"" . rawurlencode($value) . "\"";
}
$return .= implode(', ', $values);
return $return;
}
}
Edit 1
Thanks for your reply Stormdrain. I rewrote the controller as follows but I'm getting the same error again
$this->load->library('encrypt');
$this->config->load('twitter_settings');
$this->load->library('/twitter/TwitterAPIExchange');
$settings = array(
'oauth_access_token' => $this->config->item('oauth_access_token'),
'oauth_access_token_secret' => $this->config->item('oauth_access_token_secret'),
'consumer_key' => $this->config->item('consumer_key'),
'consumer_secret' => $this->encrypt->decode($this->config->item('consumer_secret'))
);
$twitter = new TwitterAPIExchange($settings);
echo $twitter->setGetfield($getfield)
->buildOauth($url, $requestMethod)
->performRequest();
Here is the error:
A PHP Error was encountered
Severity: 4096
Message: Argument 1 passed to TwitterAPIExchange::__construct() must
be an array, none given, called in
C:\wamp\www\twitter_app\theworks\core\Loader.php on line 1099 and
defined
Filename: twitter/TwitterAPIExchange.php
Line Number: 33
Make sure you are passing in the correct parameters
So when I looked at line 33 of twitter/TwitterAPIExchange.php I found this:
/**
* Create the API access object. Requires an array of settings::
* oauth access token, oauth access token secret, consumer key, consumer secret
* These are all available by creating your own application on dev.twitter.com
* Requires the cURL library
*
* #param array $settings
*/
public function __construct(array $settings)
{ //...
Just redo the $settings with the config items
$this->config->load('twitter_settings');
$this->load->library('/twitter/TwitterAPIExchange');
$settings = array(
'oauth_access_token' => $this->config->('oauth_access_token'),
'oauth_access_token_secret' => $this->config->('oauth_access_token_secret'),
'consumer_key' => $this->config->('consumer_key'),
'consumer_secret' => $this->config->('consumer_secret')
);
$twitter = new TwitterAPIExchange($settings);
Change the library load line. Remove this:
$this->load->library('/twitter/TwitterAPIExchange');
and add library like this:
require_once APPPATH.'libraries/twitter/TwitterAPIExchange.php';
class Twitter extends CI_Controller{
...
}
This solve my issue.I have used this in php codeigniter.

How to use PHP to POST to a web page then get the results back, locally

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';
?>

Categories