GetID3 analyze() function new file size parameter

You can now read ID3 (media file headers) information from mp3 and other media files using GetID3 library without having the entire media file present. The new 2nd parameter to the analyze() member function allows you to detect play time duration with only a small portion of the file present.

Years ago I added this code to the versions of the getid3 library we packaged with the Blubrry PowerPress podcasting plugin. I’ve submitted this code to the getid3 project so everyone can benefit. As of GetID3 v1.9.10,  you can now pass a second optional parameter specifying the total file size. This parameter sets the file size value in the getid3 object, skipping the need for the library call the filesize() function.

This is the secret sauce that allows PowerPress to detect the file size and duration information from a media URL of any size in only a few seconds.

Requirements

The new parameter only works if the following are true:

  • Have enough of the beginning of the media file that includes all of the ID3 header information. For a typical mp3 the first 1MB should suffice, though if there is a large image within your ID3 tags then you may need more than 1MB.
  • Have the total file size in bytes.
  • The mp3 file is using a constant bit rate. This must be true for podcasting, and highly recommended if the media is to be played within web browsers. Please read this page for details regarding VBR and podcasting.

Example Usage

// First 1MB of episode-1.mp3 that is 32,540,576 bytes
// (approximately 32MB)
$media_first1mb = '/tmp/episode-1-partial.mp3
$media_file_size = 32540576;
$getID3 = new getID3;
$FileInfo = $getID3->analyze( $media_first1mb, $media_file_size );

You can use a HTTP/1.1 byte range request to download the first 1MB of a media file, as well as a HTTP HEAD request to get the complete file length (file byte size).

Byte range requests and HEAD requests are safe to use for podcasting. If a service does not allow HEAD requests or accepts byte range requests, then they will have bigger issues to deal with as these features are required by iTunes.

Blubrry PowerPress podcasting plugin has been using this logic to detect mp3 (audio/mpeg), m4a (audio/x-m4a), mp4 (video/mp4), m4v (video/x-m4v), oga (audio/ogg) media since 2008.

Not all media formats support this option. You should test any format not mentioned above. For example, ogg Vorbis audio works, ogg Speex audio does not.

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...nn";
	// 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

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.