Sending JSON data to remote server

August 25, 2013  |  2 Comments  |  by Raj (MagePsycho)  |  jQuery, Magento, PHP

JSON: JavaScript Object Notation.
JSON is syntax for storing and exchanging text information. Much like XML.
JSON is smaller than XML, and faster and easier to parse.

You may need to post JSON data to the server for different purposes. If you are wondering about ‘How to send JSON data to remote server?’ then this article is for you. Keep on reading.

In this article, we will share different techniques to send JSON data to the server.
For one of the payment module development in Magento we had to send the encrypted password(using plain password) to the gateway page. And we will use this scenario as an example.

Suppose we have the following data:

<?php
#web service to encrypt the password (which accepts the JSON data and returns the result in JSON format)
$url	= 'http://some-payment-gateway.com/WebService/EncryptPassword';
#password to be encrypted
$plainPass = 'some-plain-password';
$data = array(
	'password' => urlencode($plainPass)
);

1. Using Ajax

var data = <?php echo json_encode($data) ?>;
var url  = '<?php echo $url ?>';
jQuery.ajax({
    type: "POST",
    url: url,
    data: JSON.stringify(data),
    contentType: "application/json; charset=utf-8",
    dataType: "json",
    success: function(data){
		var jsonObj = jQuery.parseJSON(data);
		alert(jsonObj.encPassword);
	},
    failure: function(errorMsg) {
        alert(errorMsg);
    }
});

Note: This approach can’t be used in Payment Module as we have to pass the encrypted password in hidden form fields

2. Using Curl

<?php
$content = json_encode($data);

$curl = curl_init($url);
curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_HTTPHEADER,
		array("Content-type: application/json"));
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $content);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); //curl error SSL certificate problem, verify that the CA cert is OK

$result		= curl_exec($curl);
$response	= json_decode($result);
var_dump($response);
curl_close($curl);
?>

3. Using Streams

<?php
$options = array(
	'http' => array(
		'method'  => 'POST',
		'content' => json_encode( $data ),
		'header'=>  "Content-Type: application/json\r\n" .
					"Accept: application/json\r\n"
	  )
);

$context	 = stream_context_create($options);
$result		 = file_get_contents($url, false, $context);
$response	 = json_decode($result);
var_dump($response);

4. Raw HTTP Post

Using Zend Framework’s HTTP client: http://framework.zend.com/manual/en/zend.http.client.advanced.html#zend.http.client.raw_post_data

$json = json_encode($data);
$client = new Zend_Http_Client($url);
$client->setRawData($json, 'application/json')->request('POST');
var_dump($client->request()->getBody());

These were some basic examples. If you have any other idea regarding sending json data to the remote server, please share.

is_file() vs file_exists()

March 19, 2012  |  No Comments  |  by Raj (MagePsycho)  |  Latest, Magento, PHP

Introduction

If you do not know how to use is_file() and file_exists() properly, then you will end up tearing out your hair.
Here we will talk about a scenario which will clearify the usage of is_file() vs file_exists().

Case:

We are trying to show the gallery images from a table which has the field: ‘imagepath’ for storing the path of images.
And $images holds the array of gallery images.

1. Code using file_exists()

//first case: using file_exists()
foreach($images as $_image){
	$filePath = Mage::getBaseDir("media") . DS . str_replace("/", DS, $_image->getImagepath());
	if(file_exists($filePath)){
		echo '<img src="'.$filePath.'" alt="'.$_image->getTitle().'" border="0" />'; //display image
	}
}

Notes: In this case <img> tag will be displayed in every loop even if $_image->getImagepath() is empty. why?

file_exists — Checks whether a file or directory exists

From the definition of file_exists(), it is clear that it checks whether a file or directory exists or not(don’t go with the name ‘file’ ;)).
In above case even if $_image->getImagepath() is empty (i.e. file doesn’t exists), directory does exist as it points to Mage::getBaseDir(“media”), file_exists($filePath) always return true.

2. Code using is_file()

//second case: using is_file()
foreach($images as $_image){
	$filePath = Mage::getBaseDir("media") . DS . str_replace("/", DS, $_image->getImagepath());
	if(is_file($filePath)){
		echo '<img src="'.$filePath.'" alt="'.$_image->getTitle().'" border="0" />';
	}
}

Notes: In this case <img> is displayed only if image file exists.

is_file — Tells whether the filename is a regular file

From the definition of is_file(), it is clear that if you want to check whether a file exists or not, is_file() seems to be the right choice.

So beware of using file_exists() while checking the existence of a file, is_file() is the right choice.
Hope this article makes some sense 🙂

Demystifying PHP’s Array Key/Index

February 14, 2012  |  No Comments  |  by Raj (MagePsycho)  |  Latest, Magento, PHP

According to php.net manual:

An array in PHP is actually an ordered map. A map is a type that associates values to keys.

A key may be either an integer or a string. If a key is the standard representation of an integer, it will be interpreted as such (i.e. “8” will be interpreted as 8, while “08” will be interpreted as “08”). Floats in key are truncated to integer. The indexed and associative array types are the same type in PHP, which can both contain integer and string indices.

Well that’s just a bit of defination about Array and it’s key/index.
Let’s play with some practical examples.
Suppose say you are making a dropdown field for Opacities(0, 0.1, 0.2, … 0.9, 1) for your System > Configuration field (Magento) and using your source model as:

<?php
class MagePsycho_Custommodule_Model_System_Config_Source_Opacity
{
    public function toOptionArray()
    {
        $range = range(0, 1, 0.1);
        $array = array();
        foreach($range as $val){
            $array[$val] = $val;
        }
        return $array;
    }
}

When you try to load the page in System > Configuration for your module you will see that only there is only one value in dropdown i.e.

<option value="0">1</option>

You must be wondering where are the other values (0 – 0.9)?
Now the role of key/index comes into play.

As per above defination: An array key/index can only be an integer or a string type. But here index is a float type and php will convert it to an integer type and any float value: 0.1 – 0.9 will be converted to integer: 0.

But if you modify the above code as:

<?php
class MagePsycho_Custommodule_Model_System_Config_Source_Opacity
{
    public function toOptionArray()
    {
        $range = range(0, 1, 0.1);
        $array = array();
        foreach($range as $val){
            $array["$val"] = $val; //note the double quotes around the key
        }
        return $array;
    }
}

You must have noted the double quotes around the key and using the double quotes will populate all the values from 0 – 1.
This is because PHP tries to interpolate the variable inside the double quotes and return as string. And the key looks like: For example:

$array['0.9']

which is a string key not a float one.

Hope this helps you to get some understanding of proper usage of indexing in an Array.
Thanks for Reading!

Converting multi-select field to checkbox in advanced search form of Magento

January 19, 2012  |  3 Comments  |  by Raj (MagePsycho)  |  Latest, Magento, PHP

Introduction:

Have you ever thought of modifying the default multi-select field to checkbox field in advanced search of Magento?
If not then here we will be discussing about how to do which is damn easy and much user friendlier.

Steps:

1> Copy the following file to your working theme:
app/design/frontend/[interface]/[theme]/template/catalogsearch/advanced/form.phtml

2> Open the form.phtml (from above) and find the following line just after the case ‘select’: ?>

<div class="input-box">
	<?php echo $this->getAttributeSelectElement($_attribute) ?>
</div>

and replace it by the following code

<?php if(in_array($_attribute->getAttributeCode(), array('manufacturer'))): ?>
<div class="input-box">
	<?php
		 $options = $_attribute->getSource()->getAllOptions(false);
		 foreach($options as $_option):
			 $isChecked = in_array($_option['value'], $this->getRequest()->getParam($_attribute->getAttributeCode())) ? ' checked="checked"' : null;
			 ?>
	<input type="checkbox" name="<?php echo $_attribute->getAttributeCode(); ?>[]" value="<?php echo $_option['value']; ?>"<?php echo $isChecked; ?> /> <?php echo $_option['label']; ?><br />
	<?php
		 endforeach;
	?>
</div>
<?php else: ?>
<div class="input-box">
	<?php echo $this->getAttributeSelectElement($_attribute); ?>
</div>
<?php endif; ?>

Note: Here we have customized the display for manufacturer attribute, similarly you can customize for other attributes. Just you need to add the attribute code(for example: color) in the array as:

<?php if(in_array($_attribute->getAttributeCode(), array('manufacturer', 'color'))): ?>

3> Try to refresh the advanced search page: http://your-magento-url/catalogsearch/advanced
You will see some good results 🙂

Manufacturer in default format (Before)

Customized Manufacturer Display(After)


Note: You can use some css in order to break the checkboxes in multi-columns for better display.
Hope you liked this article 🙂

Utilizing debug_backtrace() function for Magento debugging

January 14, 2012  |  5 Comments  |  by Raj (MagePsycho)  |  Latest, Magento, PHP

Introduction

As promised, back with the 2nd utility function for Magento (printDebugBacktrace).
This function will help you to print the backtrace. As you know that Magento has so many classes and flow/interlinking of those classes’ methods are really vague. So this function will help you to debug/trace in such cases.
printDebugBacktrace function looks like:

public static function printDebugBacktrace($title = 'Debug Backtrace:') {
	$output		= "";
	$output .= "<hr /><div>" . $title . '<br /><table border="1" cellpadding="2" cellspacing="2">';

	$stacks		= debug_backtrace();

	$output .= "<thead><tr><th><strong>File</strong></th><th><strong>Line</strong></th><th><strong>Function</strong></th>".
		"</tr></thead>";
	foreach($stacks as $_stack)
	{
		if (!isset($_stack['file'])) $_stack['file'] = '[PHP Kernel]';
		if (!isset($_stack['line'])) $_stack['line'] = '';

		$output .=  "<tr><td>{$_stack["file"]}</td><td>{$_stack["line"]}</td>".
			"<td>{$_stack["function"]}</td></tr>";
	}
	$output .=  "</table></div><hr /></p>";
	return $output;
}

You need to put the above method in app/Mage.php.
Note: As you see that above method utilizes the php’s debug_backtrace() method. But manually calling that function will give you very large string due to large no of complex properties & nested objects in magento classes and will be very difficult in tracing. So recommended to use the above mentioned utility function instead.

Usage

Suppose say you are trying to figure out the flow of Mage_Sales_Model_Quote_Address_Total_Shipping::collect() method.
Go to that class method and put the following line

public function collect(Mage_Sales_Model_Quote_Address $address)
{
	echo Mage::printDebugBacktrace(); exit; //add this line just after the opening
	//Mage::log(Mage::printDebugBacktrace(), null, 'backtrace.log'); //or you can even log the backtrace

And when you load the page (my cart) in frontend then you will get the following output:

Output: printDebugBacktrace


Isn’t that very helpful to know the flow and debug accordingly?
Good Luck with Magento Debugging.

EDIT:

After this article was written, found that we can do the very same thing using the following in built method:
Varien_Debug::backtrace()
Whose argument are as:

	
/**
* Prints or return a backtrace
*
* @param bool $return      return or print
* @param bool $html        output in HTML format
* @param bool $withArgs    add short argumets of methods
* @return string|bool
*/
public static function backtrace($return = false, $html = true, $withArgs = true)

So now you can simply call as

echo Varien_Debug::backtrace(true, true); exit;
//or
Mage::log(Varien_Debug::backtrace(true, true), null, 'backtrace.log');