Thursday, February 20, 2014

Magento Notes - II

Let's discuss some more Magento 1.8 stuffs ::

1. On your Cart page, how to get each product's category names?
    
   Put the following code where you want to show Category Name in  app\design\frontend\YOUR_PACKAGE\YOUR_THEME\template\checkout\cart\item\default.phtml   

<?php
   // GEt Product ID
   $proid = $this->getProduct()->getId();

   // GEt Category IDs
   $ids = $this->getProduct()->getCategoryIds();

   // Show Category Names
   $cat_name = "";

   foreach($ids as $val) 
   {
$cat_name .= Mage::getModel('catalog/category')->load($val)->getName() . ", ";
   }
   echo "Category : " . rtrim( $cat_name, ", ");
 ?>

2. How to get custom text attribute of a product?

   Suppose you have created a new text attribute called 'custom_desc'. Now, on various pages, you want to get this attribute's value. Insert any of the following codes to get it done.

   <?php
  // Method 1
  $custom_desc =  $_product->getData("custom_desc"); 
   
  // Method 2
  $custom_desc = $_helper->productAttribute($_product, nl2br($_product->getCustomDesc()), 'custom_desc'); 
   
  // MEthod 3 :: Easiest
  $custom_desc = $_product->getCustomDesc(); 
 ?>
   
   Amazing is the fact that if we create a property/attribute called "test", calling "$_product->getTest()" would return value of that property for the product "$_product". Such custom named functions will be automatically available with the product object. Check more examples below.
   
   "short_description"      => $_product->getShortDescription()
   "country_of_manufacture" => $_product->getCountryOfManufacture()
   
3. How to get Customer’s Email Address into the Order Notification Email Templates ?
  
  You need to insert the following shortcode into various email template files stored in app\locale\en_US\template\email\sales\ folder.
  
  {{htmlescape var=$order.getCustomerEmail()}}
  
4. How to identify whether current page is the home page?
   
   Use the following code snippet to help ...

   <?php
   
  $is_homepage = Mage::getBlockSingleton('page/html_header')->getIsHomePage();  
   if( $is_homepage )
   {
      // Do, if Home Page
      // However this won't work if you are sitting
      // on Home Page, but you have extra slashes in
      // URL like abcd.com/?p=2 or abcd.com/home?page=2
   }
 ?>

Another most trustworthy solution is ::

   <?php
  if( Mage::getSingleton('cms/page')->getIdentifier() == 'home' )   {
      // Do, If Home Page
      // This would work most of the times as usually 'home'
      // identifier (for page) is what we always set as Home
  }
 ?>  

5. What to do when Products are not showing up in Category page or Search results?

    1. Check if product is enabled
    2. Check product Quantity is valid. However if "Display out of stock products" is set to "yes", then products will be shown even if it has zero quantity.
    3. Check if product is assigned to a category
    4. Check Attribute settings, check if product attributes like "name" etc are "Searchable"
    5. Check if "name" attribute is having a "Global" scope
    6. Clear Cache
    7. Re-Index all the indexes

6. How to get Stock Quantity of the current product?
    
Use the following code to get current product's stock quantity. You may replace the product object "$_product" with other object you are working with.

   <?php
    $_quantity = intval(Mage::getModel('cataloginventory/stock_item')->loadByProduct($_product)->getQty());
 ?>

Check out Magento Notes - I

Magento Notes - I

Here I discuss some quick tips for Magento 1.8. 

1. How to set "One-column" template to Category Page?

   a. If you use 'base' package's 'default' theme, open app/design/frontend/base/default/layout/catalog.xml 
   
   b. If you have defined your own theme in 'default' package and overridden the above file, then open app/design/frontend/default/YOUR_THEME/layout/catalog.xml 

   Locate the following :: 
   
  <catalog_category_default translate="label">
    <label>Catalog Category (Non-Anchor)</label>

   Add the following ::  

   
  <reference name="root">
<action method="setTemplate">
             <template>page/1column.phtml</template>
         </action>
  </reference>

2. How to Resize Image in Product Listing Page ?
  
   Open app/design/frontend/YOUR_PACKAGE/YOUR_THEME/catalog/product/list.phtml

   Add the following <image> tag where necessary. We are resizing image to 218x317 (width x height). Product object "$_product" is already available to you.

   <img src="<?php echo $this->helper('catalog/image')->init($_product, 'small_image')->resize(218,317); ?>" width="218" height="317" alt="<?php echo $this->stripTags($this->getImageLabel($_product, 'small_image'), null, true) ?>" />

3. How to Resize Image in Product Details Page ?

   Open app/design/frontend/YOUR_PACKAGE/YOUR_THEME/template/catalog/product/view/media.phtml

   Add following <image> tag where necessary.

   <img id="image" src="<?php echo $this->helper('catalog/image')->init($_product, 'image')->resize(338,438);?>" alt="<?php echo $this->escapeHtml($this->getImageLabel());?>" title="<?php echo $this->escapeHtml($this->getImageLabel());?>" />

4. How to call a static block from inside the phtml file?

   If we have already defined any static block in Admin Panel, we can call it from within view (.PHTML) files. We just need to have its identifier. Then use the following code where necessary.
  
   <?php 
  echo $this->getLayout()->createBlock('cms/block')->setBlockId('STATIC_BLOCK_IDENTIFIER')->toHtml(); 
 ?>
   
   Make sure you replace the 'STATIC_BLOCK_IDENTIFIER' with the real one.

5. How to fix the error "TypeError: productAddToCartForm is undefined" Magento?
  
   This Javascript error may crop up on your product details page when "Add to Cart" to button is clicked. This happens because of the conflict between existing Prototype JS library and jQuery (which you added later).

   Simple solution is to add "jQuery.noConflict();" statement after you have included your jQuery Library file.
   
6. How to get current product's Category name?

   I assume that you have $_product object at your disposal. Then, use the code below to get Category names. A product can belong to multiple categories. 
   
<php 
  // Get All Category IDs
   $cat = $_product->getCategoryIds(); 

   // Get First Category Name
   $cat_name = Mage::getModel('catalog/category')->load($cat[0])->getName();
?>

For More, check out my next article Magento Notes - II.

Monday, February 17, 2014

Compare two Databases with PHP

Very recently I faced a big problem where I had a older DB working with new version of files. To be precise, I was working with Magento 1.8 files with Magento 1.6 database filled with various products and customer information. And frankly speaking, it landed me into deep water as various stuffs like shopping cart, checkout process, reIndexing services, catalog price updation etc started to give errors. It all happened just because new magento files are expecting new fields in the DB. So, I wrote a piece of code to match the original DB (v1.8) with my current working DB (v1.6). And very soon I was able to track down the table differences in two databases and I just manually added those extra columns which the current DB (v1.6) was lacking. Soon, all the errors on the site mostly vanished. 

Manually column addition is a bad idea because it does not create the Indexes which already exist in correct/Original DB. For that, I'll be writing another script. Till that time, check out the php code for this simple Database comparison.

Download table_comparison.php

This solution works the following way :: 

1. We connect to 2 Databases within a script. If the server allows multiple DB connection on a single script, then there won't be any problem. Otherwise we need to use a fourth parameter (true) with 2nd mysql_connect() onwards.
   
 mysql_connect( db_host, db_username, db_password, true );

2. We use a "SHOW TABLE"  query to fetch all the tables from a Database and store them in an Array. This way we create 2 arrays, first one holding all the table names from DB1 and the second one holding all table names from DB2. So, if a DB has 300 tables and another has 400 tables, that differences can be easily found by counting elements in each array.

3. Now, we would iterate through the first array (holding table names from correct database DB1); taking each table name we would run a "DESCRIBE table_name" SQL and fetch all the column names and store them in an array. Now we would do this for each table in each database and then we would match column names.

4. Reporting would be a very essential thing. We need to use various flags/counters/Strings etc to keep track of changes and use them in generating the report.

Check out some screenshots showing the output ::

























Friday, February 14, 2014

File download script using PHP

Opening a file in another window or tab within a browser, we can use an anchor to that file like this : 

<a href="test.pdf" target="_blank">Download the PDF here</a>

it will open the file in a new tab. To force the browser to download it on the viewer's PC, we need to write some server side code. Here I am showing some sample codes which would show "Save As" message box on browsers.

Setting the headers is the most important thing here. Here, code for downloading PDF file is shown. We are reading "sample.pdf" and forcing the browser to download it as "test.pdf" on viewer's machine. We can have variety on our solutions.

Solution 1 ::

<?php

/// Set the header
header("Content-type:application/pdf"); 
header("Content-Transfer-Encoding: binary");
header("Content-Disposition:attachment; filename=test.pdf");

/// Deliver the content
readfile("sample.pdf");
?>

Solution 2 ::

<?php

// GET the Source file's contents
$str = file_get_contents("sample.pdf") or die("Could not open file");

// Get the Target
$fp = fopen("php://output","w+") or die("Could not open output stream");

// Set the Header
header("Content-type:application/pdf"); 
header("Content-Transfer-Encoding: binary");
header("Content-Disposition:attachment; filename=test.pdf");

// Send Data
fputs($fp, $str);

// Close file
fclose( $fp );
?>

Solution 3 ::

<?php

// GET the Source file
$fp = fopen("sample.pdf","r+") or die("Could not open file");

// Set the Header
header("Content-type:application/pdf"); 
header("Content-Transfer-Encoding: binary");
header("Content-Disposition:attachment; filename=test.pdf");

// Read and Send Data
while( !feof($fp) )
 echo fread( $fp, 1024 );

// Close file
fclose( $fp );
?>

All the above solutions would work smoothly but the first one needs output buffering to be enabled. The 3 solutions above have different file reading and rendering methods only, the header information remain same. We are reading a file called 'sample.pdf' and forcing it to be downloaded with a default name 'test.pdf'. 

The "Content-Disposition:attachment" is very important. This would prompt for downloading the file instead of directly showing it in Browser.  

We can force the browser to download other file types like Excel file but for that we need to modify the MIME 'Content-type' in response header. For an Excel file to be downloaded we may use the following code :

<?php

// GET the Source file
$filename  = "tester.xls";
$fp = fopen($filename,"r+") or die("Could not open file");

// Set the Header
header("Content-Type:application/vnd.ms-excel; charset=utf-8"); 
header("Content-Transfer-Encoding: binary");
header("Content-Disposition:attachment; filename=genuine.xls");

// Read and Send Data
echo fread( $fp, filesize($filename) );

// Close file
fclose( $fp );
?>

The above code will download all kind of files if we correctly change the "Content-Type" settings in header(). Some content types are shown below :

If the MIME type starts with "vnd" ( in case of .ppt, .word or .xls files ), it means to be vendor specific. If the type starts with "x-", it means that it is non-standard, ( not registered with the "Internet Assigned Numbers Authority" ).

Images :: 
.png : header("Content-Type:image/png") 
.jpg : header("Content-Type:image/jpg") 
.gif : header("Content-Type:image/gif") 
.bmp : header("Content-Type:image/bmp") 

Texts ::
.txt : header("Content-Type:text/plain") 
.html : header("Content-Type:text/plain") 
.php : header("Content-Type:text/plain") 
.js : header("Content-Type:text/plain") or header("Content-Type:text/javascript") (obsolete) or header("Content-Type:application/javascript")
.xml : header("Content-Type:text/xml")
.csv : header("Content-Type:text/csv")
.css : header("Content-Type:text/css")

Video ::
.mpg : header("Content-Type:video/mpeg")
.mp4 : header("Content-Type:video/mp4")
.3gp : header("Content-Type:video/3gpp")

Audio ::
.aac : header("Content-Type:audio/x-aac")
.mp3 : header("Content-Type:audio/mpeg")

Zip ::
.7z : header("Content-Type:application/x-7z-compressed")
.bz : header("Content-Type:application/x-bzip")
.zip : header("Content-Type:application/zip")

Other ::
.pdf : header("Content-Type:application/pdf")
.xls : header("Content-Type:application/vnd.ms-excel; charset=utf-8")
.ppt : header("Content-Type:vnd.ms-powerpoint")
.doc : header("Content-Type:application/vnd.openxmlformats-officedocument.wordprocessingml.document")
.swf : header("Content-Type:application/x-shockwave-flash")
.bin/.exe : header("Content-Type:application/octet-stream")

Thursday, February 13, 2014

Text File Reading in PHP

A text file can be read in many ways, however reading PDFs or Excel files will be different because there format is complex. We usually do not need to read complex file types, so, we'll mostly stick to reading text files. 

Usually text files can be read -- i) all at once ii) character by character iii) line by line iv) in bytes. Check the code below.

First we would read the total content at once from a file. 

<?php
// Method 1
// This prints the text in original format
// file_get_contents() read the whole content 
// into a string variable $str
echo $str = nl2br(file_get_contents("test.txt"));

// Method 2 :: readfile() writes to output buffer.

// If output buffering is turned off, content won't 
// be displayed
readfile("test.txt");

// If we clean the buffer, the content is 

// not displayed on browser
readfile("test.txt");
ob_end_clean();

// Let's get all the buffered content into a string

// ob_get_clean() returns the buffer content as a string
// This again prints in content in original format
readfile("test.txt");
$str = ob_get_clean();
echo nl2br( $str );

/// Method 3 :: Grab the total content using fread()

// Open the file
$file_name = "test.txt";
$fp = fopen($file_name,"r+") or die("File can't be opened");
// GEt the total contents
echo nl2br(fread($fp, filesize($file_name) ));
fclose($fp);
?>

Now, let's try to read the character by character. Check the code below.

<?php
// Open the file
$file_name = "test.txt";
$fp = fopen($file_name,"r+") or die("File can't be opened");

// Loop every character

while( ($char = fgetc($fp))!== false )

  if( ord($char) == 13 )  
    echo "<br>";
  else
    echo $char;
}

// Close the file handle/pointer
fclose($fp);
?>

The ord() function returns the ASCII code of passed character. So, for every newline character, we are printing a <br> element to keep the original formatting.  

Next, we would be reading a file line by line using fgets() function. Check the code below.

<?php
// Open the file
$file_name = "test.txt";
$fp = fopen($file_name,"r+") or die("File can't be opened");

// Loop thru lines

while( ($str = fgets($fp))!= NULL )
 echo $str . "<br>";

// Close the file handle/pointer

fclose($fp);
?>

The above code reads all the lines one by one from beginning. To read a file line by line from the end, check the article How to read a file backward in PHP?.

Next, we would read a file byte by byte which is again done with fread().

<?php
$file_name = "test.txt";
$fp = fopen($file_name,"r+") or die("File can't be opened");

// Loop thru bytes
while ( ( $data = fread($fp, 10) )!= false )
 echo nl2br($data);

// Close file 
fclose($fp);
?>

The above code reads 10 bytes at a time including the newline character. Let's twist the output of the above program and discover some good stuffs.

Let's change the while loop as shown below :

<?php
// Loop thru bytes
while ( ( $data = fread($fp, 10) )!= false )
{
  $data = str_replace("\n","@",$data);
  $data = str_replace("\r","#",$data);
  echo "[$data]<br>";
}
?>

Suppose the file test.txt has the following content ::

Line 1 :: THIS IS JUST a TEST
Line 2 :: THIS IS JUST a TEST
Line 3 :: THIS IS JUST a TEST

and if the above code is run on Xampp or Wamp on Windows, the above file content would be perceived as following ::

Line 1 :: THIS IS JUST a TEST\r\n
Line 2 :: THIS IS JUST a TEST\r\n
Line 3 :: THIS IS JUST a TEST\r\n

Newline character on Windows is comprised of '\r' and '\n'. The output of the above code will prove that. The output is shown below :

[Line 1 :: ]
[THIS IS JU]
[ST a TEST#]
[@Line 2 ::]
[ THIS IS J]
[UST a TEST]
[#@Line 3 :]
[: THIS IS ]
[JUST a TES]
[T#@]


The above output proves i) fread() reads through newline character and ii) Newline character on Windows is '\r\n'.

The $bytes_pos holds a value 0 (zero) initially and file pointer is standing at 0th location. Then fread() function reads 10 bytes, hence the file pointer points to 10th location now which is returned by ftell(). So, this way the $bytes_pos array keeps on storing positions like 0, 10, 20, 30 40. When it comes to the reading last 10 bytes, ftell() still returns the position of current bytes (which can be EOF or a newline) within file which is stored at the last position in the array $bytes_pos. This would cause a small problem in our next example. 

Let's try a useless but a different thing with fread(). Let's read all these data packs (10 bytes each) backward. Check the code below.

<?php
$read_length = 10;

$file_name = "tester.txt";
$fp = fopen($file_name,"r+") or die("File can't be opened");

// Store the First Position 0, file reading starts from
// Position 0 within file
$bytes_pos = array(0);

// Loop thru bytes and store bytes position in an array
while ( ( $data = fread($fp, $read_length) )!= false )
 $bytes_pos[] = ftell( $fp );

// Reverse the array for reading it Backward 
$bytes_pos = array_reverse( $bytes_pos );

// Finally, reading 10 bytes from stored positions
foreach($bytes_pos as $pos)
{
  // Move the file pointer
  fseek( $fp, $pos );
  
  // Read
  $data = fread($fp, $read_length) ;
  $data = str_replace("\n","@",$data);
  $data = str_replace("\r","#",$data);
  echo "[$data]<br>";
}

// Close file 
fclose($fp);
?>

Here again, we started with reading 10 bytes and storing the position in an array $bytes_pos. The ftell() function returns the current position of file pointer. When the array is filled with various positions 10 bytes apart, we just reversed it. Then finally we iterated through the array using the foreach loop construct. Next, we used the fseek() function to move the file pointer to desired location and read 10 bytes from thereon using fread() function. Check the output below. It is almost the opposite to the previous output.

 [] [T#@]
[JUST a TES]
[: THIS IS ]
[#@Line 3 :]
[UST a TEST]
[ THIS IS J]
[@Line 2 ::]
[ST a TEST#]
[THIS IS JU]
[Line 1 :: ]

The first line "[]" is coming because of the fact that file position of EOF or newline is stored at the last location within the array. This was discussed awhile ago. However this problem can be overcome by removing the last item from that array.

Friday, November 15, 2013

Handling XML in PHP - II

If we want to generate XML in an organized way, we better use DOM extensions that comes with PHP. This creates DOMDocument object and the corresponding methods follow a pattern of adding, removing or manipulating elements and text nodes or adding attributes to DOM elements. The methods are quite similar to JavaScript DOM handling functions. 

Our first example loads an XML document using PHP DOM extension, then renders it on browser.

<?php
// Create new object
$xml_doc = new DOMDocument();
// Use load() method to load a document
$xml_doc->load('test.xml');
//Render it on screen
echo $xml_doc->saveXML();
?>

The content of test.xml is shown as output but only the text nodes. Tags are not shown. We need to view the source to get the actual XML structure. To render the whole XML structure on browser (without viewing the source), we need to include the header call : header('Content-type:text/xml'); before calling the saveXML() method.

Our next example, creates an XML document on the fly. Let's check it out.

<?php
header('Content-type:text/xml');

// Create new DOM object
$xml_doc = new DOMDocument();

// Add the root element 'students'
$students = $xml_doc->createElement('students');

// Append the new node to the doc
$xml_doc->appendChild($students);

// Now create First student Node
$student1 = $xml_doc->createElement('student');

// Create some attributes for student node
$attr1 = $xml_doc->createAttribute('id');
$attr1->value = "1";
$attr2 = $xml_doc->createAttribute('section');
$attr2->value = "A";
$attr3 = $xml_doc->createAttribute('username');
$attr3->value = "john_smith";

// Append the new attributes to the created element 'student'
$student1->appendChild($attr1);
$student1->appendChild($attr2);
$student1->appendChild($attr3);

// Now Insert a comment Node
$comm1 = $xml_doc->createComment('Teacher : Niel Hertz');
$student1->appendChild($comm1);

// Now Insert other child elements under "student" node
$fname = $xml_doc->createElement('fname');
$textNode = $xml_doc->createTextNode('John');
$fname->appendChild($textNode);

$lname = $xml_doc->createElement('lname');
$textNode = $xml_doc->createTextNode('Smith');
$lname->appendChild($textNode);

$roll_no = $xml_doc->createElement('roll_no');
$textNode = $xml_doc->createTextNode('109');
$roll_no->appendChild($textNode);

// Append all child nodes to 'student' node
$student1->appendChild($fname);
$student1->appendChild($lname);
$student1->appendChild($roll_no);

// Finally Append the 'student' node to 'students'
$students->appendChild($student1);

// Render it on screen
echo $xml_doc->saveXML();
?>

The above code generates and renders the following XML on the browser : 

<students>
 <student id="1" section="A" username="john_smith">
   <!--Teacher : Niel Hertz-->
   <fname>John109</fname>
   <lname>Smith</lname>
   <roll_no>109</roll_no>
 </student>
</students>

In the above code, we are using a DOMDocument object first, then using functions like createElement(), createAttribute(), createComment(), createTextNode() etc to create a DOM structure under it. All the created elements, attributes, comments, text nodes do not get into picture until we give calls to appendChild(). This function adds the element [or attribute etc] to its parent.

Next, we would parse an XML structure using the DOMDocument objects. Let's check out a program which loads an XML file and prints every elements and its contents on the screen.

<?php

// Create new DOM object
$xml_doc = new DOMDocument();

// Load external XML file

//$xml_doc->load('test.xml');  /// This is also OK
$xml_doc->loadXML(file_get_contents('test.xml'));

/// Get all the student element
$students = $xml_doc->getElementsByTagName('student');

//// Iterate thru each student node
foreach( $students as $stu )
{
  // Get Attributes of an element
  $id = $stu->getAttribute('id');
  $section = $stu->getAttribute('section');
  $username = $stu->getAttribute('username');
  
  // GET Child Elements/nodes and their values
  // A NodeList is returned by getElementsByTagName
  $nodes = $stu->getElementsByTagName('fname');
  $fname= $nodes->item(0)->nodeValue;

  $nodes = $stu->getElementsByTagName('lname');
  $lname= $nodes->item(0)->nodeValue;
  
  $nodes = $stu->getElementsByTagName('roll_no');
  $roll_no= $nodes->item(0)->nodeValue;
  
  $nodes = $stu->getElementsByTagName('class');
  $class= $nodes->item(0)->nodeValue;

  $nodes = $stu->getElementsByTagName('nickname');
  $nickname= $nodes->item(0)->nodeValue;


  /// Print on screen
  echo "<b>Student Details ::: </b><br>";
  echo "Name : $fname $lname [NickName : $nickname]<br>";
  echo "ID : $id, Section : $section, Class : $class<br>";
  echo "Username : $username<br><br>";
  
}

?>

The above program loads content of an XML file, then parses it and prints the student details. The functions like getElementsByTagName(), getElementById() locates elements within the XML document. The function getElementsByTagName() returns DOMNodeList class object holding all the elements found. Then we can simply use the item() method to access each element. Attributes of elements can be retrieved using getAttribute() method.

Check out the first part - Handling XML in PHP - I

Wednesday, November 13, 2013

How to check whether a remote file exists in PHP

Sometimes, we may need to execute remote php files and work on the resultant output. For example, very recently I have worked on a project in which file-checking PHP scripts on various remote servers are executed at regular intervals by a cron set on a single server at my disposal [I can control this server]. Those file-checking PHP scripts check if any file has been modified recently on its local server. This facility helps in tracking if any file has been modified by recent hacking attack.

In this situation, I needed to use CURL methods to execute the remote scripts, then get and parse the output. But I got error messages when the remote file-checking scripts were removed/deleted/renamed by hacking or any other ways. So, before executing remote scripts, we needed to check if the script existed at all.

There are many ways we can determine whether a remote script exists or not.

1. The first method is using functions like fopen()/file_get_contents()/file_exists() method. Check the code below..

<?php

/// We are trying to open the remote file in READ-ONLY mode
/// Using fopen() function 
$fp = fopen("http://example.org/file_check.php","r") or die("Could not open remote file");

/// Using file_get_contents() function
$str = file_get_contents("http://example.org/file_check.php") or die("Could not open remote file");

/// Using file_exists() function
echo  file_exists("http://example.org/file_check.php") or die("ERROR");

?>

2. The second method is using the function get_headers(). This function returns all the header sent by the server. Check the code below.

<?php

// GET the URL status
$status = get_headers( 'http://example.org/file_check.php' , 1) ;

// Check the status CODE
if( $status[0] == 'HTTP/1.0 404 Not Found' )
{
  // ... 
}

?>

The get_headers() function returns the headers in an array format and that array's zeroth position always hold the response code. 

All the above methods would require the allow_url_fopen settings in php.ini file to be set to 'On'. Otherwise they would fail.

3. The third method is to use CURL library. Check the code below.

<?php

// Init CURL
$ch = curl_init();

// set URL and other appropriate options
$curl_url = "http://example.org/file_check.php";
curl_setopt($ch, CURLOPT_URL, $curl_url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE );

// grab URL and pass it to the browser
$str = curl_exec($ch);

/// Check if the file_check.php exists
$http_status = curl_getinfo($ch, CURLINFO_HTTP_CODE);

/// HTTP Status 200 means file exists
if( $http_status == "200" )
{
   //// The result/Output is already stored in $str
   //// We will parse the value of $str
}

?>

The above program is quite self-explanatory.  The curl_getinfo() function returns the response code which is 200 in case the page exists. The CURL method does not care about the value set to allow_url_fopen directive, hence very convenient and powerful tool to use.

Wednesday, August 21, 2013

Basic Authentication with .htpasswd in Xampp (Windows)

The basic http authentication created with .htaccess and .htpasswd files works pretty well on online real server. However implementing them locally on our Xampp server (on Windows) may be a little problematic. Here I am going to discuss the steps required to achieve this.

First of all, we need 2 files need to be created, .htaccess and .htpasswd. All the user passwords are stored inside the .htpasswd file. Windows does not allow to create such nameless files, however we can create them with Command Prompt. Check the picture below.



We have used the DOS command "copy con <filename>". Pressing CTRL + Z would end the process and creates a new file with the name provided. This way, we created the required .htaccess file. Our working folder is "htpassword". We created the .htaccess inside that only.

Next we would create the .htpasswd file with the help of command 'htpasswd', the corresponding windows executable file 'htpasswd.exe' resides in xampp\apache\bin folder. So, check the next screenshot to understand how we create the password file required for authentication.



We gave the command "htpasswd -c -m -b .htpasswd admin admin_pass". "admin" is going to be the username and "admin_pass" would be our password.

-c : create a new file
-m : MD5 encryption is enforced
-b : Use the password given at the command prompt

So, our .htpasswd file is successfully created. Our working folder "htpassword" also has an index.php file which contains a one-liner welcome message.

Now, open the .htaccess file, we need to write the following lines inside it.

AuthName "My Protected Area"
AuthType Basic
AuthUserFile c:\xampp\htdocs\htpassword\.htpasswd
require valid-user


Check the third line where the path of the password file is clearly mentioned. Now when we try to go to http://localhost/htpassword, a prompt appears asking for user id and password ( this is shown in screenshot below ). If valid id and password given, then we are redirected to index.php or other file set to be the default file.