Tuesday, July 29, 2014

Handling Zip Archives in PHP - II

In our previous article Handling Zip Archives in PHP - I, we learned about how to create ZIP archive in PHP. In this discussion, we would learn how to extract files from an Archive.

Check out our first code below, this just takes a ZIP Archive and extracts all files and folders from it.

<?php
// First Create a new Object of the class ZipArchive
$archive = new ZipArchive;

// Now OPEN Archive
$result = $archive->open("our_zip.zip");

// Check if the Archive was created successfully
if($result == 1)
{
  // Extract to current Folder
  $archive->extractTo('.');

  // Close the Archive
  $archive->close();
}
else
{
  echo "Archive creation Error [Error code : $result]";
}
?>

The code above is quite self-explanatory. The extractTo() method takes 2 parameters, first being the target folder where it should extract; second parameter is for specifying filenames only which we want to extract from the Archive. We would see an example soon. But before that, check the statement :

$archive->extractTo('.');

The character "." means current folder, ".." means parent folder. However this statement could have been written as shown below ::

<?php
// Extract to Current Working Folder
$archive->extractTo(getcwd());

// Extract to 'test' folder in the current working folder.
//'test' folder will be created if does not exist.
$archive->extractTo("test");  
?>

So, we know how to create an archive and extract files from it. Next we would try to modify the archive.

Here, we are going to rename a file inside the archive. Check out the statement ..

<?php
// This renames test.jpg to tester.jpg within 'images' folder
$zip->renameName('images/test.jpg','images/tester.jpg');
?>

However, we can move a file inside the Archive while renaming. Check the statement below ::

<?php
// This renames test.jpg to tester.jpg within 'images' folder
$zip->renameName('images/test.jpg','tester.jpg');
?>

The above statement move the file 'images/test.jpg' and renames it to 'tester.jpg' and saves it at the root level within the Archive. Similarly we can rename folders and move them accordingly.

Next, let's check out how we can delete files/folders from within a ZIP archive.

<?php
// Delete a file
$archive->deleteName("images/test.jpg");

// Delete a folder
$archive->deleteName("images/");
?>

While deleting a folder, we need to make sure that the name is followed by a "/" character. Secondly, only empty folders can be removed.

To set a comment for the Archive, we need to use setArchiveComment() method.

<?php
// Set the Archive Comment
$archive->setArchiveComment('this is a test comment');

// Get the Archive Comment
$comment = $archive->getArchiveComment();
?>

Next we can read each file within the Archive. Check the statement below ::

<?php
// Read File Content
$file_content = $archive->getFromName('a.txt');

// Print the Content
echo $file_content;
?>

We can get property of individual items within the Archive ::

<?php
// Get file stats
$data = $archive->statName('a.txt');

// Print
print_r($data);
?>

And here is the ourput :: 

Array
(
    [name] => a.txt
    [index] => 9
    [crc] => -1815353990
    [size] => 177045
    [mtime] => 1406113612
    [comp_size] => 378
    [comp_method] => 8
)

It shows that the file size is 177045 bytes which was compressed to 378 bytes.

All files/folders in the Archive has an index number. So, we can delete/rename or get statics of file or do other stuffs with that index number also. Let's check that out. In the example below, we show the list of all the items inside the Archive.

<?php
// LOOP thru files
for ($j = 0; $j < $archive->numFiles; $j++)
{
   // GET filename
   $filename = $archive->getNameIndex($j);
  echo "<br>$filename";
}
?>

Check the Output ::

tester.jpg
images/contact.jpg
images/spinning.gif
images/responsive.png
images/scan0001.jpg
images/test_image.jpg
e.txt
a.txt
b.txt
c.txt
d.txt

See, the code above has listed all the files inside any sub-folders. The ZipArchive object property numFiles (used as $archive->numFiles) holds the total number of files inside the Archive.

Some more functions which take file index number ::

$archive->statIndex(index_number) => Get file statistics
$archive->renameIndex(index_number) => Rename a file
$archive->deleteIndex(index_number) => Delete a file
$archive->getFromIndex(index_number) ==> Get contents of a file

If we want to revert all the changes we did to an item within the Archive, we can use these methods ::

$archive->unchangeName("a.txt");
$archive->unchangeIndex(index_number);

Thursday, July 24, 2014

Handling Zip Archives in PHP - I

Handling ZIP archives, like reading an archive, extracting files from it or putting some files into a ZIP archive etc can be done very easily with PHP. PHP provides the ZipArchive class to create and read zip files. Please make sure that ZIP extension is installed with your version of PHP. So, let's just start with a small piece of code which creates a ZIP archive and put some files in it.

So, here is our first code snippet ... which creates a Zip archive and puts some files into it.

<?php
// First Create Object of the class ZipArchive
$archive = new ZipArchive;

// Now create an Archive 
$result = $archive->open("our_zip.zip", ZipArchive::CREATE);

// Check if the Archive was created successfully
if($result == 1)
{
  // Put a file into it
  $archive->addFile('a.txt', 'apple.txt'); 
  
  // Close the Archive
  $archive->close();
}
else
{
  echo "Archive creation Error [Error code : $result]";
}
?>

So, here is what we did ..

i. Created an object of the ZipArchive class
ii. Called open() method of that class to create our archive
iii. Added a file into the archive by calling addFile() method
iv. And finally we closed the Archive by calling close() method. 

The open() method takes various FLAGs as second argument. These FLAGs are described below.

ZipArchive::CREATE - Create Archive if it does not exist
ZipArchive::OVERWRITE - Overwrite existing Archive
ZipArchive::EXCL - Return error if the Archive already exists. 
ZipArchive::CHECKCONS - Perform additional consistency checks on Archives. Return Error if these checks fail.

If open() method worked perfectly, it returns 1 otherwise various Error codes/FLAGs described below. "ER_" prefix is for errors.

ZipArchive::ER_EXISTS - File exists - 10
ZipArchive::ER_INCONS - Inconsistent Archive - 21
ZipArchive::ER_INVAL  - Invalid arguments - 18 
ZipArchive::ER_MEMORY - Memory allocation failure - 14
ZipArchive::ER_NOENT  - File does not exist - 9 
ZipArchive::ER_NOZIP  - Not a zip archive - 19
ZipArchive::ER_OPEN   - File opening error - 11
ZipArchive::ER_READ   - File reading error - 5
ZipArchive::ER_SEEK   - Seek Error - 4

Let's complicate stuffs a bit more. In our second example, we add a file "b.txt" to the existing Archive "our_zip.zip" but inside a folder 'balloon'.

<?php
// First Create Object of the class ZipArchive
$archive = new ZipArchive;

// Now use existing Archive our_zip.zip
// See that we dont use any FLAG with open() method
$result = $archive->open("our_zip.zip");

// Check if the Archive Open was success
if($result == 1)
{
  // Put a file inside 'balloon' folder
  $archive->addFile('b.txt', 'balloon/balloon.txt'); 
  
  // Close the Archive
  $archive->close();
}
else
{
  echo "Archive creation Error [Error code : $result]";
}
?>

Was not a big deal at all, this piece of code was self-describing... So, now our sample Archive holds the following files ...

apple.txt
balloon/balloon.txt

Let's Add some Content manually to that ZIP archive. We need to use addFromString() method here. See example below..

<?php
// ... create class etc etc

// Build the String
$str = "This is a Sample String, it will be saved in a file called c.txt";

// Write the string as a file c.txt
$archive->addFromString('custom/text/c.txt', 'file content goes here');
?>

The code above would create a file custom/text/c.txt inside that zip archive (in custom/text folder) and write the content of $str variable inside it.

Next, we would browse a folder for some Image files, then put them into a Zip file. This may sometimes come very handy in a situation where a user selects some photos (or PDFs or mixed) on our website and wants them to be downloaded in a zip archive. We would use the ZipArchive class' addGlob() method. 

The scenario :: We have couple of images at the current folder, and we also have some more images in a folder called "test_images". Now, we want to take all the images ( including those in test_images folder ), create a new folder "images" inside the ZIP Archive and put into them. Check out the code below.


<?php
// First Create a new Object of the class ZipArchive
$archive = new ZipArchive;

// Now create an Archive 
$result = $archive->open("our_zip.zip", ZipArchive::OVERWRITE);

// Check if the Archive was created successfully
if($result == 1)
{
  // Set some basic Options for addGlob() method
  $options = array('add_path' => 'images/', 'remove_all_path' => TRUE);
  
  // Now use the Glob() pattern to add all images from current path
  $archive->addGlob('*.{png,jpg,jpeg,gif,bmp}', GLOB_BRACE, $options);
  
  // Add all images under a folder 'test_images'
  $archive->addGlob('test_images/*.{png,jpg,jpeg,gif,bmp}', GLOB_BRACE, $options); 
  
  // Close the Archive
  $archive->close();
}
else
{
  echo "Archive creation Error [Error code : $result]";
}
?>

This code is also very simple. We have used an array $options to create necessary options for the addGlob() method. 

i. 'add_path' => 'images/' means we wanted to create a new path 'images' inside the Archive
ii. 'remove_all_path'=>TRUE means even if we take files from 'folder1' or 'folder2' or 'test_images' ( as found by glob() ), these folder paths will be removed

addGlob() method is taking a pattern as first parameter. Check this statement once again ::

$archive->addGlob('test_images/*.{png,jpg,jpeg,gif,bmp}', GLOB_BRACE, $options); 

GLOB_BRACE flag is used to match any of the extensions provided within the curly braces {}. For more on how Filesystem's glob() function works and glob patterns, check the article Using GLOB in PHP.

We have a ZipArchive method called addEmptyDir() to create empty folders inside the Archive. Check out the statement below :

$archive->addEmptyDir("test_folder");

So, this is actually pretty simple. Check this blog for more on handling ZIP archives in PHP.

In our next article, Handling Zip Archives in PHP - II, we discuss on extracting/renaming/deleting files from the Archive.

Friday, June 06, 2014

FTP File transfer using PHP

Couple of times I have faced situations where I need to backUp all files on a server and shift to another. This becomes tedious if it is done through normal FTP clients like FileZilla or CuteFTP etc because file downloading to your local machine and uploading to the target server may take several hours. Or, if we try to download and upload via CPanel, it will take same amount time and there will be additional risk of breaking of download/upload if network connection is lost for any reason.

To avoid this huge time wastage, we can do the following things ::

1. Use CPanel to ZIP all the source files in Source server
2. Then Upload a small PHP file to Source server and run it
3. This PHP file uploads the big backup ZIP archive to the Target server through FTP
4. On the Target server, we unzip the ZIP archive 

What we would require ::

1. CPanel access of both the source and target servers
2. FTP access of target server

So, the process is pretty simple, the important part is to write the PHP file which does the main job. 

Check the PHP code below.

First we use ftp_connect() function to connect to Target server, if this connection is not established, we don't proceed further.

Secondly, use use ftp_put() function to upload the file to Target from Source server.


<?php
/// FTP Uploader Application

/// SET FTP Login details for Target Server
$ftp_server = "targetserver.com"; 
$ftp_user_name = "ftpUserName";
$ftp_user_pass = "ftpPassword";

// set up the FTP connection
$conn_id = ftp_connect($ftp_server) or die("Could not FTP Connect to $ftp_server"); 

// login with FTP username and password
$login_result = ftp_login($conn_id, $ftp_user_name, $ftp_user_pass); 

// check connection
if ((!$conn_id) || (!$login_result)) 

   echo "<br><span style='color:red'>FTP connection has failed!</span>";
   exit; 

else 
{
   echo "<br>Connected to <b>$ftp_server</b>, for user <b>$ftp_user_name</b>";
}

// GET the file, which needs to be transferred
$source_file = "public_html.tar.gz";

// Set the TARGET location
$destination_file = "public_html/public_html.tar.gz";

// upload the file
$upload = ftp_put($conn_id, $destination_file, $source_file, FTP_BINARY); 

// check upload status
if (!$upload) 

   echo "<br><span style='color:red'>FTP upload has failed!</span>";

else 
{
   echo "<br>Uploaded [$source_file] successfully to <span style='color:green'>$ftp_server</span> as [$destination_file]";
}

// close the FTP stream 
ftp_close($conn_id); 
?>

The above code is quite self-explanatory. 

There are some other FTP functions like as shown below :;

Connection Related ::
ftp_ssl_connect() :- For making Secure SSL-FTP connection
ftp_pasv()  :- Set PASSIVE mode to ON/OFF

File/Folder Edit/Delete/Rename ::
ftp_get() :- Download a File from the Target Server 
ftp_mkdir()  :- Create new folder on Target server
ftp_rmdir()  :- Remove folder from Target server
ftp_rename()  :- We can rename old folders/files on the Target server 
ftp_delete()  :- Delete a file from the Target server

Browse the Target Server :
ftp_chdir() :- Change directory
ftp_pwd() :- Get current directory in the Target server
ftp_nlist() :- Returns a list of files in the given directory

Some examples ::
ftp_chdir($conn_id,"public_html");
ftp_get($conn_id,'Ro_bo_ts.TxT','robots.txt',FTP_ASCII);

The above 2 lines, changes current directory to 'public_html' and downloads a file 'robots.txt' in ASCII mode and saves it as 'Ro_bo_ts.TxT' on local directory.

print_r(ftp_nlist($conn_id,'public_html'));
The above line Get listing of all the folders/files inside 'public_html' folder.

Wednesday, May 14, 2014

Include the text "Grand Total to be Charged" in Invoice Emails in Magento 1.7

I had this requirement in Magento 1.7 a couple of days back. Suppose, my site has multiple currencies and I check out with GBP whereas my default currency is USD. Now, the Order email has the following texts ::

...                          ... 
Grand Total                  £93.66
Grand Total to be Charged    $169.70

Which means, I purchased items costing £93.66 but I will be charged $169.70 (which is equal to £93.66 as per conversion rate on that day). But when the Invoice mail is generated, the last line "Grand Total to be Charged" is not appearing. I needed that line to appear on all other transaction emails including Invoice emails.

How I found the solution ?

To solve the problem, I started digging into the email template files first. Order_new.html and invoice_new.html were the files I started to delve in. My observations are as shown below :

1. The Invoice email template invoice_new.html has the following line ( which deals with and prints the whole PRICE stuffs ):
     
    {{layout handle="sales_email_order_invoice_items" invoice=$invoice order=$order}}

   whereas the Order email template order_new.html has the following line :

   {{layout handle="sales_email_order_items" order=$order}}

2. In sales.xml, layout handle 'sales_email_order_invoice_items' has a block template 'email/order/invoice/items.phtml'. This item.phtml file has the following line ::

    echo $this->getChildHtml('invoice_totals');

and sales.xml again says ( getChildHtml('invoice_totals') is referring to )::
   
    <block type="sales/order_invoice_totals" name="invoice_totals" template="sales/order/totals.phtml">   

3. Again, in sales.xml, layout handle 'sales_email_order_items' has a block template 'email/order/items.phtml' .. this item.phtml file has the following line ::

   echo $this->getChildHtml('order_totals');

and sales.xml again says getChildHtml('order_totals') is referring to ) :: 
   
<block type="sales/order_totals" name="order_totals" template="sales/order/totals.phtml">

4. So, both Order and Invoice emails dynamically loads "sales/order/totals.phtml" file. Now in totals.phtml file, we have a line like this :: 

foreach ($this->getTotals() as $_code => $_total): 

The above foreach construct takes output (as an array) from getTotals() function and loops through the output array containing whole Pricing structure including base price, shipping expenses, tax, discounts, Base price in other currencies etc. 

5. As the Base Price (with BASE currency as set in Admin Panel ) was coming properly in Order email, I checked the class ( from <block type='sales/order_totals' ) Mage_Sales_Block_Order_Totals found in Mage/Sales/Block/Order/Totals.php. The getTotals() function is just iterating the class property '$this->_totals'. I also checked how this '$this->_totals' array was created through '_initTotals()' method. And within this '_initTotals()' method, $this->_totals['base_grandtotal'] is being created which is responsible for printing the Order price in Base Currency and this is what I was looking for. However, this Base price was not coming in Invoice emails. Hence I opened the Class 'Mage_Sales_Block_Order_Invoice_Totals'.

6. The class 'Mage_Sales_Block_Order_Invoice_Totals' ( existing in file 'app/code/core/Mage/Sales/Block/Order/Invoice/Totals.php' ) inherits from the class 'Mage_Sales_Block_Order_Totals' and overrides the function _initTotals() which created the pricing array _totals. Check the function below :

    protected function _initTotals()
  {
     // Call Parent Mage_Sales_Block_Order_Totals
     // class' _initTotals() to create the 
     // parent class' _totals array
     parent::_initTotals();
        
     // Removing the _totals['base_grandtotal']
     $this->removeTotal('base_grandtotal');
     return $this;
  }
    
    The line $this->removeTotal('base_grandtotal'); is removing the Base Price section from the _totals array. Simply commenting the line finally solved my problem.

Magento 1.8 Notes - III

1. Get Customer's FirstName in transactional Emails in Magento ::
    
    In transactional email template files ( order_new.html/invoice_new.html etc), the following line
   
   Hello, {{htmlescape var=$order.getCustomerFirstName()}}
   
   should give the customer first name. However, in email templates (order_new.html etc) where "Hello, {{htmlescape var=$billing.getName()}}" is used, replacing this with the above mentioned "{{htmlescape var=$order.getCustomerFirstName()}}" may give full name of the  customer. In such situations, the following method would always work.
   
   The class Mage_Sales_Model_Order is defined in app\code\core\Mage\Sales\Model\Order.php file where getCustomerName(), getCustomerFirstName() etc functions are defined. We can add our own method inside this class.
   
   public function getCustomerOnlyFirstName()
 {
   // GET Name
   $name = trim($this->getCustomerName());
 
   // Find if any Space is there within Name
   $pos = strpos($name," ");
 
   // If Space is found, extract till that Space
   if($pos !== false) 
   {
     $name = trim(substr( $name, 0, $pos ));
   }
 
   // return 
   return $name;
 }
   
   and then use the line below to get the customer's first name in email templates ( where $order variable is used ) ::
   
   Hello, {{htmlescape var=$order.getCustomerOnlyFirstName()}}

2. Include Customer IP address in New Order Email template ::
   
   To achieve this, we need to follow steps shown below --
   a. Modify /public_html/app/code/core/Mage/Sales/Model/Order.php
   b. We need to edit the function sendNewOrderEmail()
   c. We nee add a new variable 'remoteaddr' or anything of our choice and set some value to it.
   
   $mailer->setTemplateParams(array(
       'order'        => $this,
       'billing'      => $this->getBillingAddress(),
       'payment_html' => $paymentBlockHtml,
       'remoteaddr'   => $_SERVER['REMOTE_ADDR']
     ));
   
 d. Now we must call the variable from within template file as {{var remoteaddr }}   

3. Get Order Comments in Transaction Email :: 
   
     Use the below line to get Customer Comments in Email Template :-
   
     {{var order.getEmailCustomerNote()}}

4. Run Installation process again : 
   
   Once, I forgot the Admin Password on Local installation of Magento, I wanted to restore it. I thought that it would be better if I could run the Installation process again. Running the Installation process again did not delete my existing data on Database. Which means it did not create new tables on the DB rather used the old ones. So my Admin Panel was intact. 
   
   To go through install wizard again, we need to delete app/etc/local.xml file and reload any magento page, it will be redirected to /install. 

5. Magento Error :: "There was a problem with the subscription: This email address is already assigned to another user."
   
   This is not a bug but an intended behaviour in Magento. This message can be seen in the following scenarios ..
   
   i. When the user is not logged in, however he/she is using an email address with which another customer is already registered.
   ii. When the user is logged in, however he/she is not using his/her own email address, rather an email address with which another customer is already registered.
   
   So, if we use a right email address, this error message can be avoided.
   
6. Get the GIANT XML file programmatically which is created after every module's config.xml file is parsed by Magento and included in the global config. 
   
   echo Mage::app()->getConfig()->getNode()->asXML() ;

Tuesday, April 29, 2014

Arrays in PHP - 2

In my previous article Arrays in PHP, I had discussed about creating and printing arrays. In this article, I would discuss some more things we can do with Arrays. But before that, let's check one complex array below :

<?php

$arr = array (
          
'name'      => 
   array('first_name'  => 'Robin', 
         'middle_name' => '', 
         'surname'     => 'Smith'),
'dob'       => '14/Jan/1980',
'lucky_nos' => array( 
         'numerology_based'    => 1, 
         'chinese_astro_based' => 2 ),
'grade_years' => array( 
         '2001' => 'A+', 
         '2002' => 'B+', 
         '2003' => 'C+' ),
'ph_nos'    => array(
         '2202-3256', 
         'father' => '4545-2256')
);

?>

In the above multi-dimensional associative array, a student info has been stored under various "key" => "value" pair combinations.

Now, if we want to add some more information to it, we would do it the following way.

<?php
$arr['favourite_color'] = array('blue','pink') ;
?>

So, a new key 'favourite_color' will be created holding an array of 'blue' and 'pink'. But, if we do it the following way ::

<?php
$arr[] = array( 'favourite_color' => array('blue','pink') ) ;
?>

next available index 0 (Zero) will be created. So all the indices within the array will be 'name', 'dob', 'lucky_nos', 'grade_years', 'ph_nos' and 0 (zero). It is same as writing the following statement (in this context)::

<?php
$arr[0] = array( 'favourite_color' => array('blue','pink') );
?>

In case of Associative arrays, the keys would have automatically casts to Integers as shown below :

<?php
$arr = array (  
        0     => 'Philippe',
        '0'   => 'John',  // String to Integer 0
0.9   => 'Mick',  // Float to Integer 0
false => 'Andrew', // 'false' is cast to Integer 0
NULL  => 'Rahman' // NULL is cast to '' 
       );

print_r( $arr );
?>  

All the index '0' (as string), '0.9' (as float/double), 'NULL' (as NULL), 'false' (as boolean) will be converted to integer 0. In case of floating point number, the fractional part is totally discarded, hence, for example, '1' will be accepted as key for given keys like '1.23', '1.67' or '1.09'. In our example above, first four keys are evaluated to 0 (zero) and hence $arr[0] will have the last value 'Andrew' as every time old value is overwritten. The key 'NULL' is cast to empty string. Check out the output below :

Array
(
    [0] => Andrew
    []  => Rahman
)
  
Copying an array to another is very simple. All the 'key'=>'value' combination are preserved while copying to another array.

<?php
// Simple copy
$arr2 = $arr;
?>

However, if we create a reference to that array, any changes to original array would reflect in the reference. Check the example below.

<?php
// Create a reference
$arr3 = & $arr;
?&gt;

Next, we would work on some array operators. Let's start with '+' operator, which unions two array. Check the example below.

<?php
// First array : index 0,1
$arr1 = array( 1, 2 );

// Second array : index 0,1
$arr2 = array( 2, 3 );

// Add them using '+' operator
// $arr1 if first operand
print_r( $arr1 + $arr2 );

// $arr2 is first operand
print_r( $arr2 + $arr1 );
?>

The output will be

Array ( [0] => 0 [1] => 1 )
Array ( [0] => 2 [1] => 3 )

In case of $arr1 + $arr2, as the $arr2 also has index '0' and '1', $arr1's (former array) values will be preserved. Hence the first print_r() print's $arr1's values.

But in case of $arr2 + $arr1, the second print_r() prints just the opposite as first operand $arr2's values are preserved. Check another example ::

<?php
// both the Arrays have indices 0 and 1
$arr1 = ('apple','banana');
$arr2 = ('mango','orange');

// Outputs array(0=>'apple', 1=>'banana')
print_r( $arr1 + $arr2 );
?>

Here the first array - $arr1's index/value pairs will be preserved as the second array also has the same indices.

If both the arrays have different key=>value combinations, the resultant array can have all the key=>value combinations as shown in the example below ::

<?php
// First array : index 0,1
$arr1 = array( 1, 2 );

// Second array : index 2,3
$arr2 = array( 2=>2, 3=>3 );

// Add them using '+' operator
// $arr1 if first operand
print_r( $arr1 + $arr2 );

// $arr2 is first operand
print_r( $arr2 + $arr1 );
?>

Here is the output

Array ( [0] => 1 [1] => 2 [2] => 2 [3] => 3 )
Array ( [2] => 2 [3] => 3 [0] => 1 [1] => 2 )

In the first case, $arr2's index and value combinations are appended to $arr1's same combination whereas in the second case, $arr1's key value pairs are appended to $arr2's same pairs.

Next, we can use operators '==', '<=', '>=' for array comparisons. Keys should match on both the arrays for such comparison. Array with lesser number of values are smaller in case of comparison. If keys are same, then values are checked. Check the example below :

<?php
$arr1 = array ( 1=>1, 2=>2 );
$arr2 = array ( 2=>2, 3=>3 );

// Uncomparable as index don't match
echo $arr1 == $arr2;

$arr1 = array ( 1=>1, 2=>2 );
$arr2 = array ( 1=>2, 2=>4 );

// $arr2 has larger values
echo $arr1 <= $arr2; // Outputs 1
?>

Let's see how to deal with situations where a function returns an array.

<?php
// Define a Function which returns array
function return_array(){ return array(1,2,3,4); }

// As of PHP 5.4, access the 3rd element
$fourth_elem = return_array()[3];

// Otherwise, store it in some
// other variable
$arr = return_array();

// Access Array Items
$fourth_elem = $arr[3];
?>


Objects and other data types can be typecast to array. Check out some examples below : 

<?php
class a
{
  private $name = 'Robin';
  private $age  = 15;
  public  $roll = 1;
  protected $ph = 909090;
}

// Create Object of class a
$obj = new a();

// Object to Array
$arr = (array) $obj ;

// Member names will be the 
// KEYS in the resultant array
print_r( $arr );

// String to Array
$name = 'Robin' ;
$arr = (array) $name;
print_r( $arr );
?>

While typecasting from Object, the member variables' names become the keys of the resultant array. For private variables, class is prepended to the key, for public variables the key is same as the variable name, for protected variable a '*' is prepended to the key. The characters/strings which are prepended to the key are wrapped by NULL (\0)  characters. These NULL characters can be seen if we var_dump() the array.

Check the output of the above code :

Array
(
    [aname] => Robin 
    [aage] => 15
    [roll] => 1
    [*ph] => 909090
)
Array
(
    [0] => Robin

)

Arrays types are very flexible in PHP. We would discuss more on it in later articles.