Posts Tagged ‘PHP’

Converting any number to a Currency (or 2 decimal places)

May 29th, 2009

Yes it sounds fairly elementary doesn’t it… yet I can’t find a PHP function to just do it?

If, like me, you store your currency values in your database as integers (don’t ask why, I just do) then you need to multiply by 100 on the way in and divide by 100 on the way out.

The obvious problem (or maybe not so obvious) is that when multiplying a number 100.1 is different to 100.10 and therefore the former needs to be converted to 100.10 for the resultant number to be correct.

The following function simply does that whilst checking for the occurence of a decimal place and concatenating .00 in that situation.

function convert_to_currency($num) {
    if (strpos($num, '.') == false) {
        $num = $num . '.00';
    } else {
        $num = sprintf("%01.2f", (float)$num);
    }
    return $num;
}

This should reliably format the number ready to be manipulated for either a database or to be directly output.

Turning an Array or Object into XML using PHP

March 25th, 2009

I have read a fair few tutorials written by others using classes and DOM functions to create XML from arrays. But what happens if you have an older PHP installation or prefer to keep things really simple as I do.

The following function declarations generate an XML string from an associative array. In my scripts that use it, it’s usually coupled with a download function so that XML is generated on the fly and then downloaded to a file. The main advantage of this is that you can write a basic import script using the SimpleXML library to restore the array at any time which makes it perfect for use as part of a backup/restore system.

WordPress stores alot of it’s sitewide data in a table called wp_options which stores a named key and a value string for each piece of information. Plugins can also use this table by using the add_option, update_option, delete_option and get_option functions passing values, arrays or objects along with a key name. This isn’t an ideal data structure but does mean that plugin writers can easily store information without bloating the database with unnecessary and often badly designed tables.

The Code..

function generate_xml_from_array($array, $node_name) {
	$xml = '';

	if (is_array($array) || is_object($array)) {
		foreach ($array as $key=>$value) {
			if (is_numeric($key)) {
				$key = $node_name;
			}

			$xml .= '<' . $key . '>' . "\n" . generate_xml_from_array($value, $node_name) . '</' . $key . '>' . "\n";
		}
	} else {
		$xml = htmlspecialchars($array, ENT_QUOTES) . "\n";
	}

	return $xml;
}

function generate_valid_xml_from_array($array, $node_block='nodes', $node_name='node') {
	$xml = '<?xml version="1.0" encoding="UTF-8" ?>' . "\n";

	$xml .= '<' . $node_block . '>' . "\n";
	$xml .= generate_xml_from_array($array, $node_name);
	$xml .= '</' . $node_block . '>' . "\n";

	return $xml;
}

Usage

You can use the above functions by generating an array or object as normal and then using the following code. The function returns the XML and you can then do with it as you wish.

$xml = generate_valid_xml_from_array($array);

Things to consider

XML doesn’t allow for numeric tags so any numbers are replaced by the content of the $node_name variable. XML also doesn’t allow for certain special characters within it’s tags and ,for this reason, the htmlspecialchars function is passed over the raw data before it is placed into the string.

You can, however make use of cdata tags which tells XML readers to essentially ‘ignore whats coming next’. See the w3schools explanation of cdata here: http://www.w3schools.com/XML/xml_cdata.asp. There is no right or wrong way to escape data but if you have problems with my script then factor in the cdata tags replacing the htmlspecialchars call and see how you get on.

Alternatively feel free to contact me by commenting on this post or using the contact form and I will work with you to get your script working.

XLS Download from PHP Class!

January 21st, 2009

Following on from my last post on creating a proper XLS spreadsheet from PHP I have just written a small class which will do all the hard work for you if necessary.

It will handle rows and columns automatically aswell as being able to be passed an array and then generating a spreadsheet download for you.

Download: XLS from PHP Example Class (783 bytes)

Sample usage is as follows:

	//Require the file
	require_once (SHARED_CLASSES_DIR . 'xls.class.php');

	//Instantiate the class.
	$xls = new xls(); 

	//Just build an example array out of test data
	$array = array(
		array(1,2,3,4,'five')
		, array('five','test' ,4,3, 0)
	);

	//Triggers the download using the passed array
	$xls->download_from_array($array);

Note that when instantiating the class you can pass a string as an argument and it will set the name of the XLS download. No need to add .xls to the end because it will do that for you.

Download: XLS from PHP Example Class (783 bytes)

Creating a Downloadable Spreadsheet from PHP

January 16th, 2009

I have written several systems that show data on a page but also provide a CSV download file either through a textarea with formatted data inside to copy and paste or via a download link and creates a file on the fly.

I recently decided that this wasn’t the best way to do it seeing as the people will want to be using Microsoft Excel to view the data. It is possible to write a spreadsheet using PHP and using an example from AppServ I started to do it this way.

The original link is included above but here is my simplified version with smaller more understandable function naming:

Download the example script here: XLS from PHP Example (723 bytes)

<?php

function xls_BOF() {
	echo pack("ssssss", 0x809, 0x8, 0x0, 0x10, 0x0, 0x0);
}

function xls_EOF() {
	echo pack("ss", 0x0A, 0x00);
}

function xls_write_cell($row, $col, $value='') {
	if (is_numeric($value)) {
		echo pack("sssss", 0x203, 14, $row, $col, 0x0);
		$value = pack("d", $value);
	} else {
		$l = strlen($value);
		echo pack("ssssss", 0x204, 8 + $l, $row, $col, 0x0, $l);
	}

	echo $value;
}

// Send Headers to set the Filename and force a download of the contents of the script
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Content-Type: application/force-download");
header("Content-Type: application/octet-stream");
header("Content-Type: application/download");

 // Put the filename in \"'s if you want it to include spaces
header("Content-Disposition: attachment;filename=" . $filename . ".xls");
header("Content-Transfer-Encoding: binary ");

xlsBOF(); //Start the Spreadsheet

xls_write_cell(0, 1, 'Column 1');
xls_write_cell(0, 2, 'Column 2');
xls_write_cell(0, 3, 'Column 3');

$row = 1;
for ($i=0; $i<2; $i++) {
	xls_write_cell($row, 0, 'Row ' . $row . ' Column ' . $i);
	xls_write_cell($row, 1, 'Row ' . $row . ' Column ' . $i);
	xls_write_cell($row, 2, 'Row ' . $row . ' Column ' . $i);

	$row++;
}

xlsEOF(); //End the Spreadsheet

exit(); //Exit the script after download

?>

IE Annoyance when downloading PDFs

September 24th, 2008

I came across this error at work and it took me a good three hours to fix! The problem was when a user tried to download a pdf file from one of our sites in internet explorer. It worked fine in Firefox though! The error message was:

The file could not be written to the cache

Luckily a far low down on Google had a sensible answer which was to add the following code (PHP) before the call to session_start();

if (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE')) {
    session_cache_limiter("public");
}

Other sites were talking about security settings in versions of IE below 6 but they didn’t really help. I thought I would post this in the hope that it helps anyone else that has the same problem.

Zen Cart Welcome Email Editor

July 31st, 2008

I’ve just dug up a script that I wrote a while back for someone. It’s not the most advanced thing in the world and it does what it says on the tin.

Within Zen Cart there is a menu on the admin pages called ‘Tools’ which has an option called ‘Email Welcome’. This script is a default Zen Cart page to simply show you what the welcome email looks like.

Screenshot 1

hint: be sure to turn on html emails and it will show you both the html and text versions (default text only is set)

I have modified this script to allow the editing of these pages if you have little or no knowledge of writing PHP although some HTML skill is required.

Zen Cart puts together a number of PHP Defines to build the welcome email and normally when you want to modify it then you have to trawl through three of four files of these defines to get to the one you want.

This script basically does that for you and parses/updates the files necessary with your new information. The following image shows the new page and i’m sure no explanation is needed to show you how to use it.

Screenshot Thumbnail 2

Known Bugs: the only thing I know to be wrong with it is that some defnes reference other defines and this script doesn’t respect that. There are only one or two defines like this so nothing to worry about unless you intend to change the name of the shop owner frequently. If you do change it, however, then just make sure you use this system to update the welcome email at the same time. Nice and easy!

Here’s the download link: Welcome Email Editor for ZenCart (5.29 kB)
UPDATE: Please make sure to chmod your languages/[language]/email_extras.php, languages/[language]/create_account.php and /languages/[language].php files (in both catalogue and admin) to be writable by apache if not this may not work.

Spoofing a Post Request

July 7th, 2008

Ever needed to test what a form does on your site without having to go through and fill the thing in over and over? Alternatively have you ever needed to emulate a post request to a callback script or similar, something which is usually done by a secure server? Well I have!

If this happens then you can emulate the request to yours (or someone elses) server from anywhere using the following code.

<?php

$params = array('http'=>array('method'=>'POST','content'=>$string));
$context = stream_context_create($params);

$fp = @fopen($url, 'rb', false, $context);

if (!$fp) {
	echo 'Failed to open file pointer.';
} else {
	$response = @stream_get_contents($fp);
	if ($response === false) {
		echo 'POST Failed!';
	} else {
		echo $response;
	}
}

?>

Usage

Basically just pass the code above a URL in the variable $url and a formatted string in the format:

key1=var1&key2=var2&…

You should really stick it in a function and wrap in an HTML form but I’m not going to do it all for you! If all goes well then you should see the response from the post request, otherwise the appropriate error message will be shown.

Security Issues

Ever considered where else you could use this script? Ever though about how some people could use this script against your site? It could potentially be used for a DOS attack against anywhere but this is NOT what I recommend it be used for,  It’s just a handy tool for sending POST requests but if you are worried by this then there are a number of things you can do to prevent it.

The best I can think of is sending a DB stored random number with each POST. When your script receives it it should check the DB and delete that record if it exists then run the form, otherwise if it doesn’t exist then display the appropriate error message.

Geocoding Addresses using Google Maps

May 19th, 2008

In my previous post I showed you how to create a beautiful Google Map for your site with controls showing Google headquarters. Some might say that this isn’t very useful, I don’t know why they think that but for those that agree here is how to get it to show any postcode or address you like.

I strongly suggest you read my other post first if you don’t know much about the Google Map API (read it here)

So…

The process of turning an address into latitude and longitude coordinates is called Geocoding and Google’s API makes it very easy to do so using a simple request to their server. We will go into the legal side later on in this post but for now lets just say that Geocoding is a server intensive process for Google and they recommend client side caching of added coordinates to avoid re-requesting coordinates if you already have them.

Getting the coordinates is actually very easy. Use the following URL in your browser (making sure to replace your API key and an address)

http://maps.google.com/maps/geo?q= ## ADDRESS OR POSTCODE ## &output=xml&key= ## YOUR API KEY ##

This URL will return some XML (if you have done it correctly) which will contain three pieces of useful information

  • Latitude
  • Longitude
  • Geocode Accuracy

If you know what country your going to be searching in then you can add another argument to the URL telling it the TLD or Top Level Domain (com, uk, etc..) to make it a little easier for Googles Geocoder:

gl=uk

We can use the returned data to create a Google map of that location but first we need to extract the coordinates. Yes we could use Javascript but where’s the fun in that (or the point)? Using PHP means all the processing is done server side so the client doesn’t need to do any sort of processing (useful for slower client computers).

Here’s how you get PHP to send the request:

$ch = curl_init();
$url = "http://maps.google.com/maps/geo?q=" . urlencode($address) . "&output=xml&key=" . $api_key;
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$return = curl_exec($ch);
curl_close($ch);

Why why why are you using CURL you ask? (what is CURL anyway?) Well..

A fair few server administrators are blocking the use for file handling functions to URLs (fopen, file, file_get_contents, etc..); This is sensible because there are exploits that malicious programmers can use to gain access to your site and start causing trouble. CURL is a little slower (I’m told) but safer (apparently).

The querystring we sent to Google passes the type of return we want (XML, KML, CSV, JSON), the address or postcode (urlencoded string) and of course our API key.

The curl options (specifically CURLOPT_RETURNTRANSFER) mean that whatever comes back from your CURL request can be stored in a variable and worked on (as opposed to echoing to the screen).

Although XML parsing in PHP is really easy (xml_parse_into_struct if your interested), it’s a bit overkill for what we need; Instead specify the output as CSV which returns a simple string that is incredibly easy to use. Something like:

200,6,42.730070,-73.690570

This breaks down into the following:

  • Request status code (success is 200, anything else means it’s broken)
  • Accuracy of search result (5 is postcode level, higher is better as far as 9 which is premise level)
  • Latitude
  • Longitude

The easiest way to get split the returned CSV string is the PHP explode function:

$array = explode(',', $csv_string);

This returns an array of values split on the delimiter specified (in this case the comma). Now the latitude and longitude can be accessed at positions 2 and 3 respectively ($array[2] and $array[3]).

So whats next?: Use the code I gave in my previous example to generate a map for an address we actually want by passing the latitude and longitude into my render_map function ($map->render_map($array[2], $array[3]);).

Some things to bear in mind:

The next step in theory would be to build up a database of geocoded coordinates next to addresses and use Google maps literally everywhere. Unfortunately (to my understanding (May 2008)) the Post Office have licensed their data and Google have to follow through on this. Basically it means that in every country except the UK you can save the coordinates wherever you like whereas here you have to geocode Google’s data on the fly EVERY page load.

If you decide this is unacceptable but don’t want to break the Terms & Conditions of Google’s API you can use a geocoding service and pay per postcode. It costs about 5 pence per geocode (Postcodeanywhere May 2008) and they allow you to store the data wherever you like.

Coming next: A find my nearest … search using google maps

If you want more information on the geocoding process then Googles explanation is here