Simple PHP Syntax Highlighting

April 19th, 2009 No comments

One benefit to working as part of a development team is that you can ask your fellow developers to look at your code and ask for help. Sending code back and forth over email can be frustrating and even counter-productive. IMO, the ideal way to share code is by simply sending a URL and letting the other developer view it in their browser with syntax highlighting. Here’s one way that does not require any external libraries and is very easy to setup:

Add this line to .htaccess

RewriteRule ^(.*)\.phps$ viewsource.php?file=$1.php [QSA,L]

This rule sends all requests for files ending in .phps to the viewsource.php file with the path as an argument.

Put the below script in the document root of your development server

<?php
 
// This script should *NEVER* be used on a production server!
// By default, it will only run on localhost. If you want to run this script on
// a staging server add the IP address of that server to $allowed_servers.
$allowed_servers = array('127.0.0.1');
 
// Set $base_dir to the root of your web directory.
$base_dir = $_SERVER['DOCUMENT_ROOT'];
 
// Make sure this script is running on an allowed server.
if(!in_array($_SERVER['SERVER_ADDR'], $allowed_servers)){
    die('Do not run this script in production!');
}
 
// Exit if no file was specified
if(empty($_GET['file'])){
    die('No file specified.');
}
 
// Ensure the requested file is inside $base_dir and that it exists
$real_path = realpath($base_dir.$_GET['file']);
 
if(strpos($real_path, $base_dir) === false || $real_path === false){
    die('Access denied or file not found.');
}
 
?>
<html>
<head>
<title><?= $real_path ?></title>
<style type="text/css">
    .num_margin {
        text-align: right;
        margin-right: 6pt;
        padding-right: 6pt;
        border-right: 1px solid gray;
    }
    .num_margin a {
        color: gray;
        font-size: 13px;
        font-family: monospace;
    }
    body { margin: 0px; margin-left: 5px; }
    div { float: left; }
</style>
 
</head>
<body>
<?php
$lines = '';
$lines_array = range(1, count(file($real_path)));
foreach($lines_array as $line){
    $lines .="<a href=\&quot;#$line\&quot; name=\&quot;$line\&quot;>$line</a><br />";
}
$content = highlight_file($real_path, true);
echo "<div><div class=\"num_margin\">$lines</div><div>$content</div></div>";
?>
</body>
</html>

Now when you visit a link like: http://localhost/info.phps it will show the source of the file.

Note: This script should never be used in production!

Categories: PHP Tags:

Setup Xdebug on OS X

February 25th, 2009 No comments

Most of the blog posts I’ve seen about getting Xdebug working on OS X insist that you must use MAMP or XAMPP to do so. But since PHP and Apache come included with OS X, it seems like overkill to use one of those packages.

Contrary to popular belief, it is possible to get Xdebug working with the OS X standard Apache/PHP installation. Here’s how I did it:

  1. Download Xdebug source
  2. Extract the xdebug tarball
  3. cd into the xdebug directory
  4. Run: phpize
  5. Run: MACOSX_DEPLOYMENT_TARGET=10.5 CFLAGS=”-arch ppc -arch ppc64 -arch i386 -arch x86_64 -g -Os -pipe -no-cpp-precomp” CCFLAGS=”-arch ppc -arch ppc64 -arch i386 -arch x86_64 -g -Os -pipe” CXXFLAGS=”-arch ppc -arch ppc64 -arch i386 -arch x86_64 -g -Os -pipe” LDFLAGS=”-arch ppc -arch ppc64 -arch i386 -arch x86_64 -bind_at_load” ./configure –enable-xdebug
  6. Run: make
  7. cp modules/xdebug.so /usr/lib/php/extensions/no-debug-non-zts-20060613 (note: your path may be slightly different)
  8. add the following line to php.ini: zend_extension=”/usr/lib/php/extensions/no-debug-non-zts-20060613/xdebug.so”
  9. Run: sudo apachectl restart
  10. Write a PHP page that calls “phpinfo();” Load it in a browser and look for the info on the xdebug module. If you see it, you have been successful!

This is simply a modified version of the README file that comes with the xdebug source. The most important tweak is step 5, which sets the correct flags for the resulting module to work with Apache as it is compiled in OS X.

Note: If you’re currently using another debugger, you will need to disable it before Xdebug will work.

Categories: PHP Tags:

Geocoding with PHP

February 24th, 2009 No comments

In my last post I mentioned geocoding using the Yahoo Geocoding API, so I thought I’d post some code to do exactly that.

For the purposes of this example, assume that we have a very simple MySQL database table with this structure:

CREATE TABLE `addresses` (
	`id` int(11) NOT NULL auto_increment,
	`street` varchar(255) default NULL,
	`city` varchar(255) default NULL,
	`state` varchar(2) default NULL,
	`zip` varchar(9) default NULL,
	`lat` float(10,6) default NULL,
	`lon` float(10,6) default NULL,
	PRIMARY KEY  (`id`)
)

Here’s the script:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
<?php
// Geocode addresses using the Yahoo Geocoding API
 
// Turning on track_errors stores the latest PHP error in $php_errormsg.
// This allows for more elegant display of the error messages without having to
// code a php error handler, which would be overkill for such a simple script.
ini_set('track_errors',TRUE);
 
mysql_connect('localhost', 'user', 'password');
mysql_select_db('database_name');
 
// Setup variables to be used later
$geocode_url = "http://local.yahooapis.com/MapsService/V1/geocode";
// Enter your custom appid here
$appid ='sample_appid';
 
// Get the addresses that have not been geocoded
$address_result = mysql_query("SELECT id, street, city, state, zip FROM addresses WHERE lat IS NULL OR lon IS NULL");
 
// If the MySQL query returned any rows, loop through them
if(mysql_num_rows($address_result) > 0){
    while ($row = mysql_fetch_assoc($address_result)){
        // appid is required for each call to the yahoo geocode API
        $row['appid'] = $appid;
        // output can be either xml or php
        $row['output'] = 'php';
 
        // Store the row id for updating the database and remove from $row array
        $id = $row['id'];
        unset($row['id']);
 
        // Build the query string for sending the request to yahoo
        $query_string = http_build_query($row, '', '&');
 
        // Get latitute / longitude
        $response = @file_get_contents($geocode_url.'?'.$query_string);
 
        if($response == false){
            // If the call to the yahoo api failed, display an error message
            echo 'ERROR: '.$php_errormsg;
        }
        else{
            // Get the results of the api call and update the database records
            $response_array = unserialize($response);
            $lat = mysql_real_escape_string($response_array['ResultSet']['Result']['Latitude']);
            $lon = mysql_real_escape_string($response_array['ResultSet']['Result']['Longitude']);
            $update_result = mysql_query("UPDATE addresses SET lat = '$lat', lon = $lon WHERE id = $id");
 
            // For each record, let the user know if the update was successful. If not, display the mysql error message generated.
            if($update_result == TRUE){
                echo "Added lattitude and longitude for {$row['street']} {$row['city']}, {$row['state']} {$row['zip']}.";
            }
            else{
                echo "Unable to add lattitude and longitude for {$row['street']} {$row['city']}, {$row['state']} {$row['zip']}
                      MySQL Error: ".mysql_error();
            }
        }
        echo '<br />';
    }
}
else{
    echo "Nothing to do.";
}
?>

The code is documented pretty well so I’ll just point out a couple things

  • The Yahoo Geocoding API can return either XML or PHP serialized objects. I chose PHP serialized objects because it’s easier to deal with for what I’m trying to do.
  • http_build_query does not exist in PHP4. To use this code with PHP4 you could use the PHP_COMPAT Pear Package or the http_build_query function from the CodeIgniter Compatibility Helper.
Categories: PHP Tags:

http_build_query() and arg_separator.output

September 25th, 2008 No comments

The other day I was using http_build_query to generate URLs to use with the Yahoo Geocoding API and kept getting back a “400 Bad Request” error back from Yahoo. The URLs were being echo’ed and looked fine, I could copy the URL and paste it in the browser address bar and get the results I was looking for.

When I finally viewed the source I saw that the urls were being created with &amp; as the separator for the variables in the query string instead of &. That explained why the url looked fine when it wsa echo’ed but didn’t work when executed.

This is where arg_separator.output comes in. This setting in php.ini determines what character(s) are used when generating URLs using the built in PHP functions. So to get my code working, I just needed to change the value to just an &:

ini_set('arg_separator.output','&');

I just wish it hadn’t taken me so long to figure that out!

Categories: PHP Tags:

Canonical redirect on IIS using PHP

September 3rd, 2008 No comments

According to the seo experts of the world, it is good practice to force your website to always use the same domain. So, instead of having your site work at both www.example.com and example.com, choose one. Once you’ve chosen which form of your site to use, it’s time to setup 301 redirects to enforce that.

If you’re using Apache, it’s very easy, just add a quick mod_rewrite rule. You can remove the www or force the use of www. But since IIS doesn’t use .htaccess files, it takes a little more effort.

Create a php.ini with the following content and upload it to your site root

[php]
cgi.force_redirect = 0
auto_prepend_file = C:\php_includes\canonical.php

Keep in mind that you’ll need to change the file path to reflect the setup of your server.

Upload canonical.php with the following contents

< ?php
// Any directory index filenames should go in here with a leading /
// This is removed when doing the redirect in order to maintain consistency,
// without this, when visiting example.com you would be redirected to www.example.com/index.htm
$index_files = array('/index.htm','/index.html','/index.php');
 
// The rewrite only kicks in if the host does not begin with www. and the code is not running
// on localhost. When developing a site I setup dev.example.com on my dev machine and use
// the same code as is on the live server, so I don't want to be redirected if I'm
// accessing the code locally.
if(substr($_SERVER['HTTP_HOST'],0,4) !== 'www.' && $_SERVER['LOCAL_ADDR'] !== '127.0.0.1'){
    $url = 'http://www.'.$_SERVER['HTTP_HOST'].str_replace($index_files, '', $_SERVER['PATH_INFO']);
    header ('HTTP/1.1 301 Moved Permanently');
    header("Location: $url");
    exit();
}
?>

Notes:

  • This method assumes that you don’t have access to modify the server settings, ie: shared windows hosting. If you are able to modify how IIS is setup I’m sure there’s a better way to do this.
  • When PHP is run as a cgi, you can overwrite the php.ini settings by putting a php.ini in the site root. So if your windows host is not running php as a cgi, this won’t work. I think that php is always run as a cgi on IIS, but I could be wrong.
  • This will only work if the site is using PHP – if you have a completely static site this won’t help you. In order to use this with a static site, you’d have to change the server settings to treat your html files as php files.
Categories: PHP Tags: