Next Image
Make the current image sticky.
Previous Image
randys.org - randys.org

Posts Tagged ‘php’

Lightty Cake: CakePHP + Lighttpd Rewrite Rules

This little snippet will also allow you to capture your query string variables should the need arise.

url.rewrite-once = (    
    "^/(css|files|img|js)/(.*)" => "/$1/$2",
    "^/([^?]*)(?:\?(.+))?$" => "/index.php?url=$1&$2"
)

Posted via email from shakeit

• • •

Scrobble This: last.fm recent tracks AJAX style

So, I’ve been reading up a bit on prototype.js and its Ajax helpers. It’s an amazing tool and helped me write the bit of info at the top of the page. It’s pretty basic, but here’s the code that does most of the work:

function lastfm()
{
    new Ajax.Request('/as/recenttracks.xml',
    {
        method: 'get',
        onLoading: function() {

    },
    onLoaded: function(transport) {
        if (transport.overrideMimeType) {
            transport.overrideMimeType('application/xml');
        }
    },
    onSuccess: function(transport) {
        var response = transport.responseXML.documentElement;
        updateLastfm(response);
    },
    onFailure: failedLastfm()
});

}

The only issue I ran into was that I was originally using the RSS flavor of recent tracks, however it didn’t split up the artist and track information. It displays it as <title>[artist] – [track]</title>. That en-dash in the middle was preventing me from using title.split() on the JavaScript side of things. Really weird.

Also, since I’m a complete newbie with Ruby, I couldn’t figure out how (read: didn’t take the time to learn) to grab the content from a remote server and serve it up to the JavaScript. I’m sure it’s pretty simple… but I was at work and in a hurry. So, being that I know PHP, I just created a script to download the file and save it to the local disk and setup a cronjob.

Here’s the PHP script:

class lastfm
{
    private $user;
    private $reports;
    private $basews;
    public $saveto;

function __construct($user)
{
    $this-&gt;user = $user;
    $this-&gt;basews = 'http://ws.audioscrobbler.com/1.0/user/';
    $this-&gt;reports = array(
        'recenttracks.xml',
        'weeklyartistchart.xml',
        'weeklytrackchart.xml',
        'topartists.xml'
    );
    $this-&gt;saveto = '.';
}

public function go()
{
    for ($i = 0; $i &lt; count($this-&gt;reports); $i++)
    {
        try
        {
            $opts = array('http' =&gt; array('method' =&gt; 'GET', 'header' =&gt; 'Content-type: text/plain; charset=utf-8'));
            $context = stream_context_create($opts);

            $fp = fopen($this-&gt;saveto.DIRECTORY_SEPARATOR.$this-&gt;reports[$i], 'w+');
            $stream = fopen($this-&gt;basews.$this-&gt;user.'/'.$this-&gt;reports[$i], 'r', false, $context);
            $string = stream_get_contents($stream);
            fwrite($fp, $string);
            fclose($fp);
            fclose($stream);
            echo 'Saved ' . $this-&gt;saveto.DIRECTORY_SEPARATOR.$this-&gt;reports[$i] . "\n";
        }
        catch (Exception $e)
        {
            echo $e-&gt;getMessage() . "\n";
        }
    }
}

public function setSaveto($path)
{
    if (is_dir($path))
    {
        if (ereg('\/$', $path))
        {
            $path = ereg_replace('\/$', '', $path);
        }
        $this-&gt;saveto = $path;
    }
    else
    {
        $this-&gt;createDir($path);
        $this-&gt;setSaveto($path);
    }
}

private function createDir($path)
{
    if (!is_dir($path))
    {
        $res = `mkdir -p $path`;
    }
}

}

I’ll hit up the Rails API Docs one of these days and write a simple Ruby script that does all the work of the PHP script. Even better would be to process the XML document using ruby that just returns a string of HTML and use Ajax.PeriodicalUpdater($(e), ...).

• • •

LiMP: Lighttpd, MySQL & PHP on OS X

In following with the LAMP, MAMP, and WAMP themes, I’ve come up with my own acronym: LiMP. Lighttpd, MySQL, PHP. Of course, this doesn’t really follow the conventions of the other acronyms (my OS isn’t represented). Mainly because adding an ‘M’ just doesn’t sound (or look) right. It’s a great setup and I recently reconfigured it so it’s a (somewhat) isolated installation that could potentially be installed on any OS X system. I also managed to get ExecWrap working properly as well.

*NB* This is a fairly technical article and requires getting your fingers dirty in the Terminal (a.k.a. comman line). If you’re not fully comfortable in the Terminal, I suggest you familiarize yourself with the Terminal. You’ll also need to have installed the latest version of Xcode.

You can build this just about anywhere on your system you like. I personally keep everything in

/usr/local/src
but you can build this anywhere you want on your system. I also like to
sudo -s
so that I’m always root when comiling and installing these things. Let’s jump in…

Create your src directories:

mkdir -p /usr/local/src && cd /usr/local/src

That’s it. Now lets dig in…

Setting up Lighttpd on OS X

I figured building this on OS X wouldn’t take too much effort and I was pretty much right. Lighttpd builds just fine on OS X but it does need some other libraries installed for certain functionality. Specifically, fastcgi and Perl Compatible Regular Expressions. These libraries install without issue as well.

First lets grab the fastcgi libraries:

curl -O http://www.fastcgi.com/dist/fcgi-2.4.0.tar.gz
tar zxvf fcgi-2.4.0.tar.gz && cd fcgi-2.4.0
./configure
make
make install
cd ..

Now lets get the PCRE libraries:

curl -O ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-5.0.tar.gz
tar zxvf pcre-5.0.tar.gz && cd pcre-5.0
./configure
make
make install
cd ..

Now for lighttpd:

curl -O http://www.lighttpd.net/download/lighttpd-1.4.12.tar.gz
tar zxvf lighttpd-1.4.12.tar.gz && cd lighttpd-1.4.12
./configure --prefix=/Library/limp/lighttpd

Hopefully, you’ll see something like this after the configure script is done.

Plugins:

mod_rewrite : enabled mod_redirect : enabled mod_ssi : enabled mod_cgi : enabled mod_fastcgi : enabled mod_proxy : enabled mod_evhost : enabled mod_simple_vhost: enabled mod_mysql_vhost : enabled mod_access : enabled mod_alias : enabled mod_setenv : enabled mod_usertrack : enabled mod_compress : enabled mod_auth : enabled mod_status : enabled mod_accesslog : enabled mod_rrdtool : enabled mod_secdownload : enabled mod_expire : enabled

If you don’t see mod_fastcgi in there, something went south.

make
make install
cp doc/lighttpd.conf /Library/limp/lighttpd/lighttpd.conf

MySQL

For MySQL, I just used the standard binary installation provided by MySQL. Therefore, we’ll need to also configure and install the libraries after installing the binary package. (Thanks to Richard Valk for his article series for this bit).

First, download and install MySQL (version 5.0.24a as of this writing) Standard binary for OS X for your platform (PPC or Intel). Once you’ve installed the package, install the StartupItem and make your life simple-er (??). After everything is setup, you should modify your

PATH
environment variable again in your ~/.bashrc file.

export PATH="/usr/local/bin:/usr/local/mysql/bin:"${PATH}

Now we have to rebuild mysql and install the shared libraries we need for building PHP. Make sure you’re still in your ’src’ directory.

curl -O http://www.stathy.com/mysql/Downloads/MySQL-5.0/mysql-5.0.24.tar.gz
tar zxvf mysql-5.0.24.tar.gz && cd mysql-5.0.24
./configure --prefix=/usr/local/mysql \
 --localstatedir=/usr/local/mysql/data \
 --libexecdir=/usr/local/mysql/bin \
 --libdir=/usr/local/mysql/lib \
 --with-server-suffix=-standard \
 --enable-thread-safe-client \
 --enable-local-infile \
 --enable-shared \
 --with-zlib-dir=bundled \
 --with-big-tables \
 --with-readline \
 --with-archive-storage-engine \
 --with-innodb \
 --without-docs \
 --without-bench \
make
make install
cd ..

Compiling PHP on OS X (with the mysqli extension)

This was fairly straight forward with the exception of GD. It took me a while to figure this out, but I was using

--with-gd=/sw
and this was confusing the compiler for some reason. When I changed it to just
--with-gd
everything compiled fine… including the mysqli extension. Here’s what my config looks like:

./configure \
 --prefix=/Lbrary/limp/php \
 --enable-fastcgi \
 --enable-force-cgi-redirect \
 --enable-mbstring \
 --with-xml \
 --with-zlib \
 --with-curl \
 --with-mysql=/usr/local/mysql \
 --with-pdo-mysql=/usr/local/mysql \
 --with-mysqli=/usr/local/mysql/bin/mysql_config \
 --with-pdo-sqlite \
 --with-sqlite \
 --with-mcrypt=/sw \
 --with-gd \
 --with-jpeg-dir=/sw \
 --with-png-dir=/sw \
 --with-zlib-dir=/sw \
 --with-xpm-dir=/usr \
 --enable-exif \
 --enable-ftp \
 --enable-libxml \
 --enable-soap \
 --enable-sockets

make && make install cp /Library/limp/php/bin/php /Library/limp/php/bin/php-cgi

I’m renaming the php binary to php-cgi because, well, that’s what it is. It’s the CGI version, not the CLI version. If you want to compile the CLI version, replace

 --enable-fastcgi \
 --enable-force-cgi-redirect \

with

 --enable-cli \

and run

make && make install
again. Only do this after you’ve renamed the php file to php-cgi. Otherwise, you’ll overwrite the cgi version with the cli version and it won’t work with fastcgi.

Building ExecWrap


I’ll have to finish this at a later date… sorry. This was originally posted to my old Wordpress blog as a Draft but got imported into Typo via the wordpress2.rb script as a published article… so I left it.

• • •

How-To: Lighttpd, ExecWrap, PHP, Wordpress & Gallery2 On A Gentoo VPS

Part of my decision to change hosting providers was to expand my knowledge of technologies. I know how to write PHP, SQL and a whole host of other languages. What I was less familiar with was the servers that run them and other parts of a hosting system (mail, dns et al). Switching to a VPS setup allowed me to explore my options in what I would run on my system and fine tune the processes to run under limited resources.

I was already familiar with Apapche and how to set that up with PHP. Apache2 makes it really easy to setup suExec with mod_suphp. Simply add “SuPHP_UserGroup $user $group” to a virtual host and viola, all PHP processes run as that user (as fastcgi). That was great and all, but on a system with limited resources, apache is dog. It sucks up way too much memory. After setting up my VPS and running all the services, I was up to about 150MB of RAM used. That’s with apache2, php, mysqld, postfix, postgrey, courier-imapd (and ssl), courier-pop3d (and ssl) and mailman (which is another memory hog, but that’s another post) running. Granted 150MB isn’t that bad for a web server, especially if you have an entire system to yourself that has 1 or 2 GB of RAM. I’m on a VPS with a mere 256MB of RAM.

Enter Lighty

Lighttpd is an open source, fast and efficient alternative to Apache. It pretty much does everything Apache does but with a much smaller footprint. Yes, it was a little more difficult to setup, but most of my troubles came from not knowing the Lighty configuration syntax. It’s not hard to master, just different than Apaches familiar tag based config files.

So far, this is what I have running on my VPS:

lighttpd (1.4.11)
php* (5.1.4) (+fastcgi)
mysql (4.1.21)
postfix (2.2.10)
postgrey (1.24)
courier (4.0.4)
openssh (4.3_p2)
tinydns (1.05)
proftpd (1.2.10)

Current memory usage:

Total: 239 MB   Used: 96 MB   Free: 143 MB

UPDATE: I recently added a Typo blog (RoR application) to one of the domains I’m hosting and my memory usage jumped a little… well, a lot really. I’m probably sitting at about 120-130 MB used at the moment.

And now the HOWTO

Configuring lighty wasn’t that hard. The hardest part was figuring out things like setting up rewrite rules for web applications like Wordpress and Gallery2 search engine friendly URLs. The other tricky part was getting ExecWrap (similar to Apache’s suExec wrapper) working properly. Well, it wasn’t that tricky, I just had some settings wrong so it appeard to be tricky. Let’s tackle the ExecWrap part first.

ExecWrap Your PHP

You’ll need to grab, build and install the ExecWrap wrapper first. It’s actually pretty straight forward. The important part is setting the correct permissions on the files involved in this setup (and using the correct UIDs and GIDs for the wrapper). For the sake of this post, I’ll skip that part. If I get enough questions about it, I’ll post a follow up on how to set this up properly.

So, here’s my setting for PHP/FastCGI setup on lighty:

fastcgi.server = (
    ".php"  => ((
            # socket - this needs to be writable by the webserver itself
            "socket"            => "/var/run/fastcgi/fastphp.socket",
            # bin-path - the path to the execwrap script -- see NB below
            "bin-path"          => "/usr/lib/php5/bin/execwrap",
            # check-local - Not 100%, but I'm pretty sure this
            # disables cheking that the local file exists
            "check-local"       => "disable",
            # max-procs - Maximum number of procs to fire up.
            # I'm pretty stingey here, but my site doesn't see
            # a lot of traffic.
            "max-procs"         => 1,
            # bin-environment
            "bin-environment"   => (
                # Howman PHP_CFGI_CHILDREN to start up
                "PHP_FCGI_CHILDREN"     => "4",
                # Maximum request (per child? i dunno)
                "PHP_FCGI_MAX_REQUESTS" => "1000",
                # UID - User ID you want the script to execute as
                "UID"                   => "1000",
                # GID - Group ID you the script to execute as
                "GID"                   => "1000",
                # TARGET - the actual script to run
                "TARGET"                =>  "/usr/lib/php5/bin/randy.php.sh",
                # CHECK_GID - this just checks the GID of the wrapper script
                "CHECK_GID"             => "1"
            ),
            # Copied from another site... not quite sure what it
            # does other than copying those env to $_ENV
            "bin-copy-environment"  => ("PATH", "SHELL", "USER"),
            # Fixes broken $_SERVER['PATH_INFO] I believe
            "broken-scriptfilename" => "enable"
        )
    )
)

The contents of randy.php.sh:

#!/bin/sh
exec /usr/lib/php5/bin/php-cgi

NB: Note that the execwrap script must be executable by lighty and must also have the SUID bit set. Also, the shell script needs to be owned by the user in which you wish to execute PHP as (in my case, my username). Also note that execwrap can live anywhere you specify when you compiled the script. In my case, I specified in the execwrap_config.h /usr/lib/php5/bin as the path where it will live. The shell script must also live under the same path.

Wordpress & Gallery URLs

Permalinks. The best thing since sliced bread. The applications work flawlessly with Apache (if you can use .htaccess in your setup) but take a little tweaking in lighttpd.

Wordpress

I futzed around with this for several hours trying to get this to work properly. Trying to get my head around regular expressions and all the different possible links used in Wordpress. And it all came back to to a really simple lighttpd setting (which oddly enough, doesn’t involve rewite at all).

server.error-handler-404 = "/content/index.php?error=404"

That’s it. That and make sure your permalinks setting doesn’t contain the /index.php/.

Update: The above solution to Wordpress’ permalinks might not be the best. The fact that it’s using the 404 handler might send a 404 response back to the browser. The other issue to worry about is whether or not this is sending a temporary redirect (301). If you have content indexed by a search engine, this will ruin your page ranking. 2008-06-06

Gallery2

Gallery was a bit more difficult. Well, not really. I ended up doing a little R&D (i.e. Rob & Duplicate) from the gallery2 codex.

url.rewrite = (
    "^/(.*)/Rewrite.txt$" => "/$1/Works.txt",
    "^/gallery/v/(\?.+|\ .)?$" => "/gallery/main.php?g2_view=core.ShowItem",
    "^/gallery/admin[/?]*(.*)$" => "/gallery/main.php?g2_view=core.SiteAdmin&amp;$1",
    "^/gallery/d/([0-9]+)-([0-9]+)/([^\/]+)(\?|\ )?(.*)$" =>
    "/gallery/main.php?g2_view=core.DownloadItem&amp;g2_itemId=$1&amp;g2_serialNumber=$2&amp;$3",
    "^/gallery/v/([^?]+)/slideshow.html" =>
    "/gallery/main.php?g2_view=slideshow.Slideshow&amp;g2_path=$1",
    "^/gallery/v/([^?]+)(\?|\ )?(.*)$" =>
    "/gallery/main.php?g2_view=core.ShowItem&amp;g2_path=$1&amp;$3",
    "^/gallery/c/add/([0-9]+).html" =>
    "/gallery/main.php?g2_view=comment.AddComment&amp;g2_itemId=$1",
    "^/gallery/c/view/([0-9]+).html" =>
    "/gallery/main.php?g2_view=comment.ShowAllComments&amp;g2_itemId=$1",
    "^/gallery/p/(.+)" =>
    "/gallery/main.php?g2_controller=permalinks.Redirect&amp;g2_filename=$1"
)

Make sure you change out the ^/gallery/ parts to where you have Gallery2 installed.

Happy Little VPS

All in all, the VPS is running really smoothly. I have everything I had (thechnology wise) at Dreamhost but with twice the performance. My site is defintely faster on the VPS than it was on Dreamhost.

Stay tuned for more HOWTOs on setting up these things on a Gentoo Arch Linux VPS. I plan on writing something for a Postfix/Courier virtual domain setup at some point. If you find this useful, pass it along. I’d be real interested in seeing how this server performs under a heavy load. Perhaps you Digg it?

• • •

Google Friendly URLs with PHP and Apache

Dynamic websites are essential for content heavy sites and chances are, you’re not going to create one static page for every single page/article/product item you have stored in a database. This means you’re going to need to pass parameters to your script to pull the right content from your database. Up until recently, most people didn’t give much thought to those nasty URLs with all those ampersands (&) and equal signs and how they affect spidering by search engines. While these URLs are perfectly valid, they tend not to get indexed by Google (and other search engines) unless you submit each URL for indexing (which can cost you money). And these days, if you’re not in Google, you’re not being found.

Enter PHP and Apache

<p><p>If you&#8217;re using <span class="caps">PHP</span> and Apache, you can still be dynamic and be spidered by all the popular search engines fairly easily. Of course, this depends on your hosting provider and how much control they let you have in terms of htaccess. <span style="font-style: italic;">.htaccess </span>files let you manipulate some Apache settings on a per host/per folder basis. Have a look at the <a href="http://httpd.apache.org/docs/">Apache manual</a> for a full listing of configuration settings for Apache web server.</p></p>


<p><p>Now for the goods. Here&#8217;s a basic rundown of how search engine friendly URLs can be used in a dynamic way. Let&#8217;s say you have a catalog of items, and your script takes 3 parameters: &#8216;section&#8217; , &#8216;action&#8217;, and &#8216;item.&#8217; Normally, when passing parameters to a script, your url will look something like this:</p></p>


<p><pre><code>/index.php?section=widgets&#38;action=view&amp;amp;item=327</code></pre></p>


<p><p>With the proper directives in an Apache .htaccess file and some simple <span class="caps">PHP</span> scripting, you can turn that <span class="caps">URL</span> into something like this:</p></p>


<p><pre><code>/catalog/section/widgets/action/view/item/327</code></pre></p>


<p><p>Looks like a bunch of folders, but it&#8217;s not. &#8216;catalog&#8217; is actually a file (a <span class="caps">PHP</span> file) without the extention, and with the help of a <span style="font-style: italic;">.htaccess</span> file,  Apache treats it like a <span class="caps">PHP</span> script.  Here&#8217;s what the <span style="font-style: italic;">.htaccess</span> file looks like:</p></p>

ForceType application/x-httpd-php

That’s it. Nothing too complicated. Now for the trickier part, grabbing those parameters from the URL with PHP.

<p><p>There&#8217;s a server variable that gets passed to the script calle &#8216;PATH_INFO&#8217; which contains the entire string after the catalog file (including that first slash). To grab it in a <span class="caps">PHP</span> script, you&#8217;d use the <a href="http://us2.php.net/manual/en/reserved.variables.php#reserved.variables.server">$_SERVER</a> global variable (a la $_SERVER[&#8216;PATH_INFO&#8217;]). The idea is to <a href="http://us2.php.net/manual/en/function.explode.php">explode</a> the string into an array and loop through them to get the parameters. Here&#8217;s a small function to do so:</p></p>


<p><pre><code>&lt; ?php

function getArgs() { $params = explode(“/”, $_SERVER['PATH_INFO']); } ?>

<p><pre><code>for($i = 1; $i &lt; sizeof($params); $i = $i + 2)

{ $args[$params[$i]] = $params[$i+1]; } return $args;

<p><p>When used on the above example, this function will return an array like so:</p></p>


<p><pre><code>Array (
 [section] =&gt; widgets
 [action] =&gt; view
 [item] =&gt; 327

)

<p><p>Implimenting this into a current site shouldn&#8217;t be too hard. The &#8216;catalog&#8217; script would simply be a wraper script where you can pass the required values into existing code.</p></p>


<p><p>If you find that your web host doesn&#8217;t allow use of .htaccess files, or they don&#8217;t allow the &lt;Files&gt; directive to be used, you can do one of two things (and I highly recommend the first).</p></p>


<p><p>1) Change hosts! I use <a href="http://www.dreamhost.com/rewards.cgi?sesser">Dreamhost</a> and they are extremely flexible, have an awsome support team and have a <a href="http://www.dreamhost.com/rewards.cgi?sesser/shared/comparison.html">very good deal for $9.95/mo</a>.</p></p>


<p><p>2) Just use a normal <span class="caps">PHP</span> script (i.e. catalog.php) and use the same function. While this method works, I&#8217;ve read that some search engines see this as a hack/cheat and might not spider the pages anyway. However, if you are a reputable business, you can usually contact them and get your pages indexed.</p></p>

Other Web Servers

<p>If you&#8217;re running <span class="caps">IIS</span> (god forbid), there is hope for you. There is at least one product (ISAPI) available that mimics the Apache mod_rewrite module. This <span class="caps">ISAPI</span> can help do the same thing (although it won&#8217;t be quite as easy). But the drawbacks are that a) the <span class="caps">ISAPI</span> isn&#8217;t free and b) if you&#8217;re in a shared environment, you can&#8217;t use it. There are other ways to manipulate your <span class="caps">IIS</span> settings to use search engine friendly URLs, but they all have their downsides. Bottom line: stop using <span class="caps">IIS</span>.</p>


<p>As for other servers, I can&#8217;t really say. Chances are there are some tweaks that can be made to the configuration and/or scripts. If you know of any, please drop me a line and I&#8217;ll try to get it posted.</p>
• • •

All content Copyright © 1999 — 2010 Randy Sesser | Happily Hosted by WebFaction
Entries (RSS) | Comments (RSS)