Laravel Inheritance Fail - php

I'm using Laravel 4 and I have this code here:
http://demo.php-pastebin.com/2sfuOUE7
Above the first line there is a line where I include another class file (CHPPConnection, which is a library for easier implement of OAuth 1.0, located at http://pht.htloto.org)
This is the code for the retrieveAccessToken method in that library:
/**
* Get access token for chpp application
*
* #param String $oauthToken
* #param String $verifier
*/
public function retrieveAccessToken($oauthToken, $verifier)
{
$params = array(
'oauth_consumer_key' => $this->consumerKey,
'oauth_signature_method' => $this->signatureMethod,
'oauth_timestamp' => $this->getTimestamp(),
'oauth_nonce' => $this->getNonce(),
'oauth_token' => $oauthToken,
'oauth_verifier' => $verifier,
'oauth_version' => $this->version
);
$signature = $this->buildSignature(self::OAUTH_SERVER.self::ACCESS_URL, $params, $this->oauthFirstTokenSecret);
$params['oauth_signature'] = $signature;
uksort($params, 'strcmp');
$url = $this->buildOauthUrl(self::OAUTH_SERVER.self::ACCESS_URL, $params);
if($this->canLog())
{
$this->log("[OAUTH] Access url: ".$url);
}
$return = $this->fetchUrl($url, false);
$result = explode('&', $return);
foreach($result as $val)
{
$t = explode('=', $val);
$$t[0] = urldecode($t[1]);
}
if(isset($oauth_token))
{
$this->setOauthToken($oauth_token);
if($this->canLog())
{
$this->log("[OAUTH] Access token: ".$oauth_token);
}
}
if(isset($oauth_token_secret))
{
$this->setOauthTokenSecret($oauth_token_secret);
if($this->canLog())
{
$this->log("[OAUTH] Access token secret: ".$oauth_token_secret);
}
}
}
Why is my code not working? Why the __constructor method returns results I want, but the something method doesn't? I probably have some wrong understanding how inheritance works in this case, so please help me out!

I think it's maybe because you are trying to return something in your constructor, so maybe when you instantiate it, you aren't retrieving an instance of it but an instance of pht, which obviously wouldn't have the something() function you are looking for.
class PhtController extends BaseController {
protected $_pht;
public function __construct()
{
$this->_pht = new CHPPConnection(
Config::get("pht.consumerKey"),
Config::get("pht.consumerSecret"),
Config::get("pht.callback"));
//this returns true
}
public function something()
{
$at = $this->_pht->retrieveAccessToken($_REQUEST["oauth_token"], $_REQUEST["oauth_verifier"]);
//vardump $at here dumps just NULL and cannot use any other methods aswell, returns false
}
}
// If you need to retrieve the instance of pht for any reason, call this function rather than returning it in the constructor.
public function getPHT()
{
return $this->_pht;
}

Related

PrestaShop backend, Fatal error in ajax call

On the backend of a PrestaShop site I'm using this function:
public function hookAjax($action, $id_product, $id_lang, $title, $descript, $order, $id = NULL)
{
/* various code*/
$this->context->smarty->assign(
array(
'block_define' => $this->getFormDesc($id_product)
)
);
return $this->context->smarty->fetch($this->local_path.'views/templates/hook/admin_extra_desc.tpl');
}
public function getFormDesc($id_product) {
$array = array();
foreach (Language::getLanguages() as $lang) {
/*various code*/
foreach($result as $k=> $r) {
$files = array();
$helper = new HelperImageUploader();
$helper->setMultiple(false)->setUseAjax(true)->setName('thumbnail_'.$r['id'].'_'.$r['id_lang'])->setFiles($files)->setMaxFiles(3)->setUrl('../modules/module-name/imgAjaxCall.php?');
$result[$k]['img-form'] = $helper->render();
$result[$k]['img'] = $result[$k]['img'] ? _PS_BASE_URL_.__PS_BASE_URI__.'modules/module-name/upload/'.$result[$k]['img'] : '';
}
$array[$lang["id_lang"]] = array(
'lang_data' => $lang,
'count' => count($result),
'data' => $result
);
}
return $array;
}
HookAjax is called by:
<?php
include(dirname(__FILE__).'/../../config/config.inc.php');
$context = Context::getContext();
$addDesc = Module::getInstanceByName('module-name');
echo $addDesc->hookAjax($_POST['action'],$_POST['id_prodotto'],$_POST['lang'],$_POST['title'], $_POST['text_desc'], NULL, $_POST['row']);
?>
But I struggle with this error:
Fatal error: Call to a member function addJs() on a non-object in {my_site}/classes/helper/HelperUploader.php on line 257
You need to include init.php in HookAjax after including config.inc.php so that controller is initialized in context.
include(dirname(__FILE__).'/../../init.php');
Note that this is just bad practice, respect the MVC and use proper controllers for your AJAX calls and data validation/processing in them, not inside main module class.

Generating a php object, two levels deep

I'm new to php - objects and arrays, especially. Coming from a JavaScript world, I'm having a modicum of trouble understanding the right way to construct objects, that may easily be iterated.
I'd like to create an object (or array - although I suspect an object would be more suitable) with the following structure:
$client_body:
$cst:
$title: 'Unique string'
$copy: function_result()
$ser:
$title: 'Unique string'
$copy: function_result()
$imp
$title: 'Unique string'
$copy: function_result()
...
I've been trying with variations on the following, but with numerous errors:
$client_body = new stdClass();
$client_body->cst->title = 'Client case study';
$client_body->cst->copy = get_field('client_cst');
$client_body->ser->title = 'Our service';
$client_body->ser->copy = get_field('client_ser');
...
And it seems that, using this approach, I'd have to use a new stdClass invocation with each new top-level addition, which seems a little verbose.
Could someone point me in the right direction?
You can just typecast an array to an object:
$client_body = (object)array(
"cst" => (object)array(
"title" => "Unique string",
"copy" => function_result()
)
);
You can try this object class more OOP:
<?php
class ClientBody{
protected $cst;
protected $ser;
protected $imp;
public function __construct($cst = '', $ser ='', $imp = '')
{
$this->cst = $cst;
$this->ser = $ser;
$this->imp = $imp;
}
public function getCst()
{
return $this->cst;
}
public function getSer()
{
return $this->ser;
}
public function getImp()
{
return $this->imp;
}
public function setCst($value)
{
$this->cst = $value;
}
public function setSer($value)
{
$this->ser = $value;
}
public function setImp($value)
{
$this->imp = $value;
}
}
$myObject = new ClientBody('toto', 'titi', 'tata');
echo $myObject->getCst(); // output 'toto'
echo $myObject->getSer(); // output 'titi'
echo $myObject->getImp(); // output 'tata'
Or you could use json_decode($client_body, TRUE);

Issues calculating signature for Amazon Marketplace API

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.

Passing code to Closure/Annoymous function dynamically

I wanted to create closure with dynamic code. To do that I wrote below code :-
function generateFunction ($class, $method){
$code = "require_once 'Init.php';";
$code = '$model = new '.$class.'();';
$code .= '$model->'.$method.'();';
return function() use(&$code){
return eval($code);
};
}
I know eval is evil but unable to find any alternative yet.
To get the function in variable I used below code :-
$myNewFunction = generateFunction ('svn', 'update');
Now I want to run this function by passing it as argument to my PHP file. But this function has same body on the output while I expected it to be like below.
function(){return eval(require_once 'Init.php';$model = new svn(); $model->update())}
Basically this need arise when I decided to integrate the Jobby.
Basically this need arise when I decided to integrate the Jobby.
I assume you want to create callback functions dynamically. Then your code is complete overkill and also doesn't need eval at all. You can get the same results by passing this as callback:
$callback = array(new SVN, 'update');
That's essentially all your code does anyway. Though with the difference that SVN is instantiated here, not when the callback is triggered. For an eval-free version of your code, this'll do:
function generateFunction($class, $method) {
return function () use ($class, $method) {
require_once 'Init.php';
$model = new $class;
return $model->$method();
};
}
To complete your answers, here is a complete example with jobby :
$jobby = new \Jobby\Jobby();
$WebSitesSchedule = new WebSitesSchedule();
$WebSitesSchedule->load_all();
foreach ($WebSitesSchedule as $WebSiteSchedule)
{
$Url = $WebSiteSchedule->ScheduleAction.'?'.$WebSiteSchedule->ScheduleParameters;
$jobby->add( "CmsSchedule_".strval($WebSiteSchedule->ScheduleID), array(
'command' => generateFunction($Url),
'schedule' => $WebSiteSchedule->ScheduleCron,
'output' => '/PATH/log/CmsSchedule.log',
'enabled' => true,
'debug' => true,
'recipients' => 'toto#gmail.com'
));
}
function generateFunction($Url)
{
return function () use ($Url)
{
$Result = Proxy::curl_request($Url);
if($Result["status"]==="success")
{
print_r($Result);
return TRUE;
}
else
{
print_r($Result);
return FALSE;
}
};
}
$jobby->run();
In your case you don't need to use eval(). You have to use call_user_func (or call_user_func_array) in conjunction with class_exists and method_exists instead.
require_once 'Init.php';
function generateFunction ($class, $method) {
if (!class_exists($class)) return false;
$model = new $class();
return method_exists($model, $method)? array($model, $method) : false;
}
$myNewFunction = generateFunction ('svn', 'update');
if ($myNewFunction) call_user_func($myNewFunction);

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.

Categories