Archive for the ‘PHP’ Category

Integrating PHP Command Line Scripts with Existing Web Projects

After reading the post on Johan Mares site about the PHP command line interface, I thought I would indulge in the details how I’ve been using the PHP cli for some of my web based applications.

First, some of my web apps have multiple configuration files which are determined by the $_SERVER['HTTP_HOST'] value. If (stricmp( $_SERVER['HTTP_HOST'],’compiledweekly’) ) { // then I load compiledweekly config file }. So with that in mind, I had to add to the top of my cli scripts the following line:

$_SERVER['HTTP_HOST'] = ‘compiledweekly.com’;

This required me to have to edit the command line script every time i used it with another site. Here’s the trick: pass arguments to your command line so your script can parse them. Here’s how I did it to also include a verbose mode.

	if( count($argv) > 1 )
	{
		for( $x = 1; $x < count($argv); $x++ )
		{
			switch($argv[$x])
			{
				case '--verbose': { // Print results to std out
					$Verbose = true;
				}; break;
				case '--host': { // Print results to std out
					$_SERVER['HTTP_HOST'] = trim($argv[$x+1]);
				}; break;
			}
		}
	}

	if( $Verbose ) echo "Starting script...\n\n";
	// Continue with your script below

So with the following example I can run my script for my compiledweekly.com site with verbose information. Example:

/path/to/script.php --verbose --host compiledweekly.com

Now if you use your php script in a cron task, don't include the --verbose and make sure you check the $Verbose flag before printing any results. Don't forget to add to the end of the command line " > /dev/null 2>&1" minus the quotes, this sends any std out and std error messages to a black hole.

If your command line script is saved in a web accessible folder, here's a line you should add to the top so no web browser can execute your script:

if( php_sapi_name() != 'cli' ) die('Access denied.');

This will take your command line apps to a new level while giving you the ability to use existing web code.

PHP Function HTTP Status Code Value as String

I’ve been working with the php CURL library and found that it would not return an error if the server returned a 500 error. After looking up 3 different status codes that I wasn’t very familiar with, I created the following function. It is very complete and includes additional WebDAV, Apache and Microsoft codes.

function http_status_code_string($code, $include_code=false)
{
	// Source: http://en.wikipedia.org/wiki/List_of_HTTP_status_codes

	switch( $code )
	{
		// 1xx Informational
		case 100: $string = 'Continue'; break;
		case 101: $string = 'Switching Protocols'; break;
		case 102: $string = 'Processing'; break; // WebDAV
		case 122: $string = 'Request-URI too long'; break; // Microsoft

		// 2xx Success
		case 200: $string = 'OK'; break;
		case 201: $string = 'Created'; break;
		case 202: $string = 'Accepted'; break;
		case 203: $string = 'Non-Authoritative Information'; break; // HTTP/1.1
		case 204: $string = 'No Content'; break;
		case 205: $string = 'Reset Content'; break;
		case 206: $string = 'Partial Content'; break;
		case 207: $string = 'Multi-Status'; break; // WebDAV

		// 3xx Redirection
		case 300: $string = 'Multiple Choices'; break;
		case 301: $string = 'Moved Permanently'; break;
		case 302: $string = 'Found'; break;
		case 303: $string = 'See Other'; break; //HTTP/1.1
		case 304: $string = 'Not Modified'; break;
		case 305: $string = 'Use Proxy'; break; // HTTP/1.1
		case 306: $string = 'Switch Proxy'; break; // Depreciated
		case 307: $string = 'Temporary Redirect'; break; // HTTP/1.1

		// 4xx Client Error
		case 400: $string = 'Bad Request'; break;
		case 401: $string = 'Unauthorized'; break;
		case 402: $string = 'Payment Required'; break;
		case 403: $string = 'Forbidden'; break;
		case 404: $string = 'Not Found'; break;
		case 405: $string = 'Method Not Allowed'; break;
		case 406: $string = 'Not Acceptable'; break;
		case 407: $string = 'Proxy Authentication Required'; break;
		case 408: $string = 'Request Timeout'; break;
		case 409: $string = 'Conflict'; break;
		case 410: $string = 'Gone'; break;
		case 411: $string = 'Length Required'; break;
		case 412: $string = 'Precondition Failed'; break;
		case 413: $string = 'Request Entity Too Large'; break;
		case 414: $string = 'Request-URI Too Long'; break;
		case 415: $string = 'Unsupported Media Type'; break;
		case 416: $string = 'Requested Range Not Satisfiable'; break;
		case 417: $string = 'Expectation Failed'; break;
		case 422: $string = 'Unprocessable Entity'; break; // WebDAV
		case 423: $string = 'Locked'; break; // WebDAV
		case 424: $string = 'Failed Dependency'; break; // WebDAV
		case 425: $string = 'Unordered Collection'; break; // WebDAV
		case 426: $string = 'Upgrade Required'; break;
		case 449: $string = 'Retry With'; break; // Microsoft
		case 450: $string = 'Blocked'; break; // Microsoft

		// 5xx Server Error
		case 500: $string = 'Internal Server Error'; break;
		case 501: $string = 'Not Implemented'; break;
		case 502: $string = 'Bad Gateway'; break;
		case 503: $string = 'Service Unavailable'; break;
		case 504: $string = 'Gateway Timeout'; break;
		case 505: $string = 'HTTP Version Not Supported'; break;
		case 506: $string = 'Variant Also Negotiates'; break;
		case 507: $string = 'Insufficient Storage'; break; // WebDAV
		case 509: $string = 'Bandwidth Limit Exceeded'; break; // Apache
		case 510: $string = 'Not Extended'; break;

		// Unknown code:
		default: $string = 'Unknown';  break;
	}
	if( $include_code )
		return $code . ' '.$string;
	return $string;
}

HTTP Code values are taken from the Wikipedia entry found here: http://en.wikipedia.org/wiki/List_of_HTTP_status_codes

CW10 – May 22, 2008 – Zend PHP 5 Certification Study Guide and Open Flash Charts

Angelo discusses the Zend PHP 5 Certification Study Guide 2nd edition and explains how to implement Open Flash Charts into your PHP project.

Don’t forget to E-mail comments and suggestions to compiledweekly AT gmail.com.

Links:

Download This Episode

Columbus PHP Meetup tonight – The Art of SQL Tuning for MySQL

If you’ve been following my Twitter (@AngeloMandato) lately, you may have herd me mention previous Columbus PHP Meetups. These meetups are great for meeting fellow PHP programmers in the Columbus area and a great way to learn about different libraries, techniques and frameworks that are available.

Columbus PHP Meetup web site: http://php.meetup.com/93/

Tonights meetup topic is “The Art of SQL Tuning for MySQL” presented by Jay Pipes from MySQL. I can’t wait to attend this meetup and gain some insightful knowledge how to tune MySQL. Ever since I started my career, I’ve encountered many issues either with server loads and/or time due to poorly written queries. I think I’ve done a decent job deploying indexes, grouping like queries together, etc… but I know there is more to learn.

The past two Columbus PHP Meetups covered the Zend Framework and CakePHP. Both were great presentations.

The Zend Framework presentation from February was very informative. The Zend Framework was written in a way that the developer can decide how much he/she wants to use from the framework. This makes it possible to easily add the Zend Framework to an existing project. I think the word framework may not be the best word to describe it though, perhaps it should be called library and framework. Many parts of the Zend Framework are really just libraries to help with things like email, XML-RPC, OpenID, Flickr, Amazon, etc… I now plan on using parts of the Zend Framework in some of my projects.

I learned a lot from the CakePHP presentation from March as well. CakePHP is definitely a “framework” with all of the University taught thinking of object oriented programming and separating presentation with logic integrated. What I found interesting is CakePHP took somewhat of a Ruby on Rails like approach in managing your SQL queries. I think this type of development is fine for small to medium size projects but anything where you need full control of the queries or presentation you may find yourself feeling restricted. The presentation side of things reminds me of Smarty Template Engine, which my past experience with Smarty started out great but ended with frustration that I couldn’t add the logic I wanted at the presentation level.

I would like to learn more about CodeIgniter. CodeIgniter is the application framework that Joe used for developing the registration system for PodCamp Ohio.

PHP 5 Study GuideRelated news, I purchased a copy of the Zend PHP 5 Certification Study Guide. I own a copy of the Zend PHP 4 Certification Study Guide and loved the book till the pages started falling out. It is not just for those who want to be certified in PHP, the content is perfect for a developer who already knows how to program but just wants something to reference for the language. You should already have some background in C/C++/Java/PHP before you read this book though. I’m very pleased with this addition as well as the first one. I think I may order the Guide to Programming with Zend Framework next.

So are you attending PHP meetups in your area? If so, what sorts of things are you learning?

Line-bar graphs and Pie charts for your web application

Open Flash ChartIf you ever needed to display reports of information in a visual way in your web application then you’ll appreciate Open Flash Chart.

This flash based charting library has everything. From line graphs, bar graphs, pie charts, mixed line/bar graphs and more with the ability to add hovers, custom colors, sizes and web links. The quality of these charts is remarkable. If you have ever used Google Analytics, these charts and graphs match, if not surpass, in quality.

PHP code to format Program Name for 1-click zune subscription

ZuneI added the Zune 1-click subscription option to the RawVoice properties at www.blubrry.com and www.techpodcasts.com. I ran into an issue where show titles that contain special characters, such as quotes, would break the rest of the web page.

Below is the solution I implemented for the problem.

Fix

<a href=”< ?php
$title_for_zune = ereg_replace(‘[^A-Za-z0-9 ]‘, ”, $show_title);
$title_for_zune = str_replace(‘ ‘, ‘_’, $title_for_zune);
echo ‘zune://subscribe/?’.$title_for_zune.’=’.$feed;
?>” title=”Add to Zune”>Add to Zune</a>

Having spaces in the URL does not validate, so I replace spaces with the _ character. If you are not worried about HTML validation, you can remove the str_replace function call.

I am not sure who came up with this protocol for the add to Zune 1-click subscription, as it does not appear to be very well thought out. Most other sites like Digg only require the feed url, which will never contain characters that could break your web pages.  As Jason Van Orden points out, the format is more complex than it needs to be.

Source for Lighttpd mod_redirect rewrite module to use status code 302

Lighttpd web server, also known as Lighty, is an excellent web server and has potential to replace Apache completely.  I am slowly migrating web sites that use feature specific settings in Apache to use Lighty.  A few months ago I ran into a problem with Lighty’s ModRewrite alternative for rewriting URLs.  Lighty uses two separate modules to handle internal rewrites and Location: redirects.  It uses the common HTTP 301 Moved Permanently status code.  For most circumstances, this works well but in some cases the application may require that the redirect only be temporary and return the HTTP 302 Found status code.  Instead of modifying the mod_redirect.c source and changing the http_status code value from 302 to 301, I added new code to support a new url.redirect parameter url.redirect-found.

I’ve posted the source to the Lighttpd bug tracking system in hopes it will be added to a future version of Lighty.  http://trac.lighttpd.net/trac/ticket/1446

This addition should help the Lighty web server to be capable of handling the appropriate HTTP status codes for all situations that may arise for the web site in question.

Lighty Web Server Fast with static pages

Three months ago I started looking at an alternative web server to serve URL redirects.  The need arose when I found that Apache web server would consume a lot of system memory when testing simulated spikes to the server.  Apache could handle between 1,200 to 1,700 requests a second.  Though the number of requests per second was satisfactory, the memory usage when these simulated spikes was concerning.

I did some research and came across Lighttpd web server, also known as Lighty.  Lighty took some time to figure out, but once I did I found the XML style configuration files were not hard to implement and understand.  I did find the rewriting to be rather limited in comparison to the mod_rewrite module found in Apache.  Never the less, I was able to duplicate the rewrite that I had in Apache in Lighty.  For my application, I did have to modify the Lighty source code that way redirects returned a 302 HTTP response (It defaulted to 301 without any way of changing in the configuration files).

After performing similar tests with the same server configured with Lighty, I found that Lighty could handle between 3,900-4,100 requests per second.  On top of this, memory usage was minimized to only a fraction of the total memory available on the server.  Processor usage did increase, but was not substantial enough to warrant the change.

I am currently experimenting with combining Lighty with Apache services on one server in order to utilize the best of both worlds.  See my post on the lighttpd.net forums: http://forum.lighttpd.net/topic/13830

Lighty may be able to also serve dynamic PHP files using FastCGI faster than Apache.  I am still concerned that PHP will not function correctly since it is not multi-threaded friendly.  I also have security concerns based on what I’ve seem with source code being exposed with a popular web site recently, I am not ready to take on that much risk.

AJaxMyTop – mtop for the web browser

If you like to monitor MySQL, you are going to love this application.

http://ajaxian.com/archives/779

AJAXMyTop is a simple web application that allows you to monitor the currently executed queries on your MySQL server.  It is pretty useful, especially when you are trying to diagnose page loading issues.

Serious shortcomings with PHP5 get_headers() function

I was writing some code to find out if a file exists on a server and if it does, have it return the size in bytes.  I found a useful function built into PHP 5, get_headers().  For getting file sizes, it works flawlessly.  For situations where the file does not exist on the server, the behavior of this function was less than desirable.

Be forewarned, none of the user contributed get_headers() functions on the get_headers() documentation page on PHP.net will replicate the behavior of PHP 5’s get_headers() for URLs that use the ‘Location:’ redirect header or return File Not Found headers.

According to RFC1945, A user agent should never automatically redirect a request more than 5 times, since such redirections usually indicate an infinite loop.  For true compatibility, the functions below should be able to handle up to 5 Location redirects within one function call.  Only the native get_headers() function exhibits this behavior.  None of the user contributed functions on PHP.net handle the ‘Location’ redirection.

The native PHP >= 5 get_headers() function will not return headers in some instances where the user contributed functions would.  For example, if the server returns a 404 status, get_headers() will throw a PHP warning.  Unfortunately, the 404 error can only be known by looking at the headers.  From first glance, all of the user contributed functions will return 404 headers, which may be a desired effect but does not replicate the behavior of the native get_headers() function.

The function I created is included below.  It works well if the file exists.  Unfortunately for the project I am using the code for, I also need to verify if the file exists on the server.  I will not be able to use this function.

<CODE>
function remotefsize($url) {
$sch = parse_url($url, PHP_URL_SCHEME);
if (($sch != “http”) && ($sch != “https”) ) {
return false;
}
$headers = array_change_key_case(get_headers($url, 1),CASE_LOWER);
if ((!array_key_exists(“content-length”, $headers)))
return false;
if( is_array($headers["content-length"]) )
return array_pop($headers["content-length"]);
return $headers["content-length"];
}
</CODE>

Blubrry player!