Cakephp 2.x Security::cipher not providing results across two apps - php

I have 2 apps communicating with each other. The 1st app is the one who do the transactions and the other app is a settings app to control the 1st app's system settings.
Upon on reaching the login page of the first app, I'm calling a WebService through curl inside the config.php and it will communicate to the 2nd app and it will return corresponding values. Now, my problem is, the value was encrypted using the Security::cipher() function and it was encrypted using a module inside of the settings app. When I try to decrypt it, there is no error prompted and even no error is logged in the error logs file. I suspect that when I decrypt from WebServicesController it doesn't read the Security component. I tried to put App::uses('Security','Utility') on the top of the codes. Here's how I code it:
1st app
curl_setopt($ch, CURLOPT_URL, Configure::read('TMSWebServices.Url').'getSystemSetting.json');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
$result_json = curl_exec($ch);
curl_close($ch);
$result = json_decode($result_json, true);
debug($result); exit;
2nd app
App::uses('AuthComponent', 'Controller/Component');
App::uses('UsersController', 'Controller');
App::uses('Security','Utility');
class WebServicesController extends AppController {
public $name = 'WebServices';
public $uses = array('Tenant', 'TbNextId', 'ReportMaster' );
public $components = array('RequestHandler');
public function getSystemSetting(){
$this->loadModel('SystemSetting');
$results = $this->SystemSetting->find($type, $params);
$return_value = array();
$return_value = $results['SystemSetting'];
foreach($return_value['Config'] as $key=>$value){
if ($value['ENCRYPT_IND'] == 'Y'){
$encryptedValue = $return_value['Config'][$key]['SYSTEM_SETTING_VALUE'];
//decrypt the value
$decryptedValue = Security::cipher($encryptedValue,
Configure::read('Security.salt')); // the problem starts here
$return_value['Config'][$key]['SYSTEM_SETTING_VALUE'] = $decryptedValue;
}
}
}
}
$this->set(array(
'return_value' => $return_value,
'_serialize' => array('return_value')
));
When I try to just put simple value on the $return_value, the communication works. But if I use the Security::cipher to decrypt, it doesn't work and give me a null value.

I would look at two problems:
The Security.salt value is usually not the same across two CakePHP apps. From your error message I think that it's either empty or not set (i.e. null). Unless you set Security.salt to the same value in both apps, cipher will not work giving you either null or some incorrect value.
As #ndm mentioned in the comment, you are creating a flat array (not an associative array) so I wonder how it is that your code even enters the foreach loop.
Look at the following code and my comments:
// ...
$return_value = array(); // we have ourselves an empty array
$return_value[] = $results['SystemSetting']; // we assign a value to $return_value[0]
foreach($return_value['Config'] as $key=>$value){ // no such key 'Config' in the array
// loop code follows, but execution flow shouldn't enter here...
While we are at it, I strongly encourage you to not use Security.salt because it is just a weak XOR cipher, try to use Security.encrypt() and Security.decrypt()

Related

Method appears to be called twice

I have an application where users will enter accommodation details including the cost per night and then select the appropriate currency from a drop down. I am then using fixer.io to show the cost in both the currency it was entered in as well as converted to the user's default currency.
The cost is stored in the database as an integer. I have methods convertToInteger and convertFromInteger that take the currency, look up how many subunits there are and do the appropriate math.
There is also a formatCurrency method to format according to currency. And a convertBetweenCurrency method for the actual conversion.
The convertFromInteger method is called inside the formatCurrency method.
The $cost_per_night_entered works fine and displays the correct amount and formatting. However, the $cost_per_night_user appears to be converted from Integer twice - it is always out by that unit. So, $148 is displayed as $1.48.
I've tried using Laravel's fresh() and refresh() to no avail. Is this related to 'nesting' the calls together? I don't think I've done something dumb like call it twice - but fresh eyes may prove otherwise :)
Controller show method:
$cost_per_night_entered = formatCurrency($accommodation->cost_per_night, $accommodation->currency, getLocale($accommodation->country));
$cost_per_night_user = formatCurrency(convertBetweenCurrency($accommodation->cost_per_night, $accommodation->currency, Auth::user()->currency), Auth::user()->currency, request()->server('HTTP_ACCEPT_LANGUAGE'));
Model methods:
function formatCurrency($amount, $currency_code, $locale)
{
$value = intval(convertFromInteger($amount, $currency_code));
$money = new Money\Money($value, new Money\Currency($currency_code));
$currencies = new Money\Currencies\ISOCurrencies();
$numberFormatter = new \NumberFormatter($locale, \NumberFormatter::CURRENCY);
$moneyFormatter = new Money\Formatter\IntlMoneyFormatter($numberFormatter, $currencies);
return $moneyFormatter->format($money);
}
function convertBetweenCurrency($amount, $from_currency, $to_currency)
{
$endpoint = 'convert';
$access_key = 'xxx';
// initialize CURL:
$ch = curl_init('http://data.fixer.io/api/'.$endpoint.'? access_key='.$access_key.'&from='.$from_currency.'&to='.$to_currency.'&amount='.$amount.'');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// get the JSON data:
$json = curl_exec($ch);
curl_close($ch);
// Decode JSON response:
$conversionResult = json_decode($json, true);
// access the conversion result
return intval($conversionResult['result']);
}
function convertFromInteger($amount, $currency_code)
{
$currencies = PragmaRX\Countries\Package\Countries::currencies();
$currency = $currencies->where('iso.code', $currency_code)->toArray();
return $amount / (1 / $currency[$currency_code]['units']['minor']['majorValue']);
}

Alternative of file_get_contents function

I am trying to get json data from https://nepse-data-api.herokuapp.com/data/todaysprice.
I use file_get_contents() function but I got below error msg
Message: require(): https:// wrapper is disabled in the server
configuration by allow_url_fopen=0
Now my problem is I am using shared hosting so allow_url_fopen = 1 is not possible.
How can I get the data from above url.
In localhost this code is working properly, Here is my code
$url = 'https://nepse-data-api.herokuapp.com/data/todaysprice';
$raw = file_get_contents($url);
$data = json_decode($raw);
In case you’re using PHP to retrieve data from a certain server you probably came across the problem that it may work for you but a client complained about lots of errors. It’s pretty likely that you’ve relied on the fact that allow_url_fopen is set to true. This way you can put pretty much anything – local path or a URL – into function calls like include or maybe simplexml_load_file.
If you’d like to get around this problem you can advice your client to make the necessary changes in his php.ini file. Most of the time this isn’t an option because the hosting company decided to disable this feature for security reasons. Since almost everybody got cURL installed we can use this to retrieve data from another web server.
Implementation
I’ll present a wrapper that helps you loading an XML file. It uses simplexml_load_file if allow_url_fopen is enabled. If this feature is disabled it employs simplexml_load_string and cURL. If none of this works we’ll throw an exception because we weren’t able to load the data.
class XMLWrapper {
public function loadXML($url) {
if (ini_get('allow_url_fopen') == true) {
return $this->load_fopen($url);
} else if (function_exists('curl_init')) {
return $this->load_curl($url);
} else {
// Enable 'allow_url_fopen' or install cURL.
throw new Exception("Can't load data.");
}
}
private function load_fopen($url) {
return simplexml_load_file($url);
}
private function load_curl($url) {
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$result = curl_exec($curl);
curl_close($curl);
return simplexml_load_string($result);
}
}
//For Json
class JsonWrapper {
public function loadJSON($url) {
if (ini_get('allow_url_fopen') == true) {
return $this->load_fopen($url);
} else if (function_exists('curl_init')) {
return $this->load_curl($url);
} else {
// Enable 'allow_url_fopen' or install cURL.
throw new Exception("Can't load data.");
}
}
private function load_fopen($url) {
$raw = file_get_contents($url);
$data = json_decode($raw);
return $data;
}
private function load_curl($url) {
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$result = curl_exec($curl);
curl_close($curl);
$data = json_decode($result);
return $data;
}
}
The code is pretty simple, create an instance of the given class and call the loadXML method. It’ll call the right private method which finally loads the XML. Loading some XML is just an example, you can use this technique with e.g. include or require too.

cURL function returning false in simple GET request

I am working on this for 2 hours and just can't figure out what's wrong. I am making a cURL get request with just the URL (with parameters) and the response is expected to be some kind of access_token in JSON format but I am continually getting an error: the curl_exec() function is returning false. The URL is alright because directly pasting the prepared URL to the browser address bar gives the appropriate access_token. You may need to know that I am making a graph API (Facebook) request. Here is some code:
private function getAccessToken() {
$uri = $this->prepareTokenUri(); // getting the uri
echo "<strong>$uri</strong><br/>"; // printing the uri for debugging purpose
$this->setCurlToGet($uri); // explained below
$response = curl_exec($this->curl);
echo "<b>Here Goes Response</b>";
var_dump($response); // boolean false
$response = json_decode($response, true);
$this->token_expires = $response['expires_in'];
$this->token_type = $response['type'];
return $response['access_token'];
}
The function setCurlToGet() just does the following:
// call this function only when making a GET request
private function setCurlToGet($url) {
$this->unsetCurl();
$this->curl = curl_init();
curl_setopt($this->curl, CURLOPT_URL, $url);
curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, true);
return $this->curl;
}
and the unsetCurl() method is as follows:
private function unsetCurl() {
if(!is_null($this->curl)) {
curl_close($this->curl);
$this->curl = null;
}
}
I have var_dumped() everything, the cURL resource variable ($this->curl) and it is actually a curl resource variable. The call to curl_exec() is returning false and I just can't figure out why. Again, I would like to repeat that there is nothing wrong with the URL because when the printed url (in the line echo "<strong>$uri</strong><br/>";) is copied and pasted in browser's address bar, result is an access_token that I need.
In case you wanted to see the pattern of URI that prepareTokenUri() is preparing:
https://graph.facebook.com/v2.3/oauth/access_token?client_id={my-appid}&redirect_uri={response-handler-script-uri}&client_secret={app-secret-code}&code={a-long-code}
The quick fix:
Add these lines to your setCurlToGet function in same area as other curl_setopt methods.
curl_setopt($this->curl, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($this->curl, CURLOPT_SSL_VERIFYPEER, 0);
The only issue with this is that if someone is able to make dns go to their server, instead of facebook as expected from url, that you are not verifying that it is indeed facebook.
So if you are worried about that, the proper fix:
1) Download cacert.pem from https://curl.haxx.se/ca/cacert.pem
2) Add the following line to php.ini, with correct path of where you put the above file
curl.cainfo=/path/to/cacert.pem
3) Reload apache service

WordPress/Codeigniter Integration - Pass WP shortcode attribute to CI script

I have successfully integrated WordPress with Codeigniter. I have created a plugin that adds a shortcode that can be used in the editor. This also works as expected. Here is my code:
function get_property_filters($atts) {
foreach ($atts as $key => $value) {
$_POST['property_type'] = $value;
}
return 'Something to replace shortcode in WP Page';
}
add_shortcode('property_filters', 'get_property_filters');
What I need to do is send a POST variable from my WP plugin to a CI script, hence the line:
$_POST['property_type'] = $value;
I understand that the return value of the function that handles the shortcode is meant to replace the shortcode with some text or widget, etc in the Page/Post. I plan to replace the shortcode with an empty string. But, within the function that handles the shortcode, how can I send a POST variable to my Codeigniter script?
I have searched for hours on this. It seems to be a very specific question. Your help is appreciated.
EDIT: I had a thought about using session variables to save the value, but it doesn't seem like I can set a session variable in WP and access it from CI. Any suggestions along this line of thought?
EDIT 2: I also had the idea to query the WP database from the CI script using $wpdb. It is possible to do this and already works in some scenarios, however, I cannot get the post_content field directly from the WP database, instead I get the rendered text. i.e. My shortcode is replaced with the word "land", but I want the query to return the shortcode that was used in the WP page, not the replacement string.
If you want to send a POST data directly into a CodeIgniter script, you can use PHP's cURL library (make sure it is installed in your web server).
Important: First you will need to disable CodeIgniter's CSRF check. You could disable from the entire framework, or you could create a pre-system hook to disable CSRF in a specific controller.
Here is an example of a cURL request in your WP script:
$value = "POST VALUE";
$post_data = array();
$post_data["property_type"] = $value;
$codeigniter_url = "http://example.com/codeigniter/handle_post";
$post = curl_init();
curl_setopt($post, CURLOPT_URL, $codeigniter_url); //The URL to send the request
curl_setopt($post, CURLOPT_POST, count($post_data)); //Amount of POST fields
curl_setopt($post, CURLOPT_POSTFIELDS, $post_data); //The POST data.
curl_setopt($post, CURLOPT_RETURNTRANSFER, TRUE); //Returns the output from the requested script
curl_setopt($post, CURLOPT_SSL_VERIFYPEER, FALSE); //Do not verify the SSL certificate.
//The variable below will have the output from your Controller function in CodeIgniter.
$result = trim(curl_exec($post));
//The variable below will have any possible errors from the cURL request.
$errors = trim(curl_error($post));
//Now you can work with the $result variable which contains the results from your CI
//Controller.
Then, you can create your controller to handle your post request in CodeIgniter:
class Handle_post extends CI_Controller {
public function index()
{
$property_type = $this->input->post("property_type");
//Your actions here...
echo "RESULT FROM THE CONTROLLER IN CODEIGNITER";
}
}
For more information about PHP's cURL library, you can read the manual.
Best regards.
Just for addition to your approach regarding retrieval of content from Wordpress DB.
You can also make use of REST web-service means then from CI you only need to call the url and which correspondingly provides the required data in json or any format that you like.
And for creating a web-service inside WordPress, you can make use of this plugin :
https://wordpress.org/plugins/json-api/
I had to solve this using a completely different solution than any of the ones I mentioned above. The code below still needs to be tweaked, but you can get the idea.
I had to add this function to my WP plugin:
function save_shortcodes_to_db($content) {
global $post;
$postID = $post->ID;
global $wpdb;
if (has_shortcode($content, 'property_filters')) {
$filterArr = array('area=', 'prop_type=', 'agent=', 'office=');
foreach ($filterArr as $filter) {
$filterpos = strpos($content,$filter); //63
if ($filterpos !== false) {
$filterstrlen = strlen($filter); //10
$filterendpos = $filterpos + $filterstrlen - 1;
$offset = $filterendpos;
$valuestartpos = $filterendpos + 1;
$endbracket = ']';
$endbracketpos = strpos($content,$endbracket,$offset);
$valuelen = $endbracketpos - $valuestartpos;
$meta_value = substr($content,$valuestartpos,$valuelen);
$meta_key = 'rc_'.rtrim($filter,'=');
$data = array('post_id' => $postID, 'meta_key' => $meta_key, 'meta_value' => $meta_value);
$wpdb->insert('wp_postmeta', $data);
}
}
}
return $content;
}
add_filter( 'content_save_pre' , 'save_shortcodes_to_db' , 10, 1);
Then, in my CI controller index function, I added this:
global $wpdb;
if ($this->session->userdata('referer')) {
$pageurl = $this->session->userdata('referer');
$pos = strpos($pageurl,'listings');
if ($pos !== false) {
$page_by_path = get_page_by_path($pageurl);
$postid = $page_by_path->ID;
$content = $wpdb->get_col("SELECT post_content FROM $wpdb->posts WHERE ID=".$postid.";");
$prop_type_meta_value = $wpdb->get_col("SELECT meta_value FROM $wpdb->postmeta WHERE post_id=".$postid." AND meta_key = 'rc_prop_type';");
$data['wp_content'] = $content[0];
}
}
Basically, before the WP page is updated, my WP function saves some information from the shortcode(s) that were entered into the page by the end user to the postmeta table in WP. Then, my controller function retrieves the information, and uses it in the rest of the code. The only issues I still need to address are:
when the WP page is new, there will not be a post_id
I need to replace values in the WP postmeta table that have already been set for the page
I am sure these are easily fixed. As for a solution to the original question - set data in WP and retrieve it in CI - this answer is complete.

phpUnit - Functions in test class that aren't tests

I'm doing some speed comparisons between reports in phpunit, as I am trying to figure out an optimization problem.
I have a couple of functions that aren't necessarily tests, but don't belong in the functionality of the project either. I am using them in order to make my tests small and readable. The function I am using does a cUrl operation with the parameters I pass to it.
So, I am running two Urls (two versions of a project, one in its original form, and one with the optimization) and seeing if they return text equal to each other. I would not do this within the app itself. I'm doing this because its quicker than trying to figure out the correct function calls because the project is a bit messy.
So I have a test like this:
public function testOne(){
$results = $this->testRange(13,1,2013,16,1,2013);
$this->assertEquals($results['opt'], $results['non_opt']);
}//tests
And my two non test functions:
protected function testRange($fromDay,
$fromMonth,
$fromYear,
$toDay,
$toMonth,
$toYear){
$this->params['periodFromDay'] = $fromDay;
$this->params['periodFromMonth'] = $fromMonth;
$this->params['periodFromYear'] = $fromYear;
$this->params['periodToDay'] = $toDay;
$this->params['periodToMonth'] = $toMonth;
$this->params['periodToYear'] = $toYear;
$this->data['from']=$fromDay."-".$fromMonth."-".$fromYear;
$this->data['to']=$toDay."-".$toMonth."-".$toYear;;
return $this->testRunner();
}//testOneDay
protected function testRunner(){
//include"test_bootstrap.php";
$response = array();
foreach($this->types as $key=>$type){
$params = http_build_query($this->params);
$url=$this->paths[$type];
$curl_url = $url."?".$params;
$ch = curl_init($curl_url);
$cookieFile = "tmp/cookie.txt";
if(!file_exists($cookieFile))
{
$fh = fopen($cookieFile, "w");
fwrite($fh, "");
fclose($fh);
}//if
curl_setopt($ch,CURLOPT_COOKIEFILE,$cookieFile);
curl_setopt($ch,CURLOPT_COOKIEJAR,$cookieFile);
curl_setopt($ch,CURLOPT_FOLLOWLOCATION,1);
curl_setopt($ch,CURLOPT_HEADER,0);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
$result[$type] = curl_exec($ch);
$dump = "logs/report_results/".
$this->data['from']."_".
$this->data['to']."_".
$type.".txt";
$fh = fopen($dump, "w");
fwrite($fh, $result[$type]);
fclose($fh);
}//foreach
return $result;
}//testRunner
I'm wondering if
A: it is possible to write functions in the test file, and have phpunit ignore them, or if there is a more appropriate place to put them.
B: there is a more sensible way to handle this sort of thing. I like this approach, but I am open to suggestions.
PHPUnit will ignore any method whose name does not start with "test*" and do not have a #Test annotation so feel free to put stuff in private helper functions.

Categories