Salient Digital Techno Blog

Ramblings on technology with a dash of social commentary
RSS icon Email icon Home icon
  • How to install PHP 5.4 or PHP 5.3 on Mac OS X Yosemite

    Posted on December 14th, 2014 PHP Guru No comments

    Yosemite comes with Apache 2.4 & PHP 5.5 preinstalled. You don’t need MAMP, only MySQL or MariaDB.

    Regardless, you can use PHP 5.5, PHP 5.4 or PHP 5.3 as needed. Try the following…

    sudo mv /usr/local/bin/php /usr/local/bin/php55
     sudo mv /usr/bin/php /usr/bin/php55

    Install PHP 5.4

    brew install php54 php54-mcrypt php54-mysql

    Install PHP 5.3

    brew unlink php54
     brew install php53 php53-mcrypt php53-mysql

    Switch to PHP 5.4

    brew unlink php53
     brew link php54

    Switch to PHP 5.5

    brew unlink php54
     brew unlink php53
     sudo ln -s /usr/local/bin/php55 /usr/local/bin/php
     sudo ln -s /usr/bin/php55 /usr/bin/php

  • How to start MySQL on Mac OS X

    Posted on December 14th, 2014 PHP Guru No comments


    macpro:~ me$ mysql.server start
    Starting MySQL
    . ERROR!

    macpro:~ me$ sudo mysql.server start
    Starting MySQL
    . SUCCESS!

  • Extending Apple Apache & PHP with Homebrew

    Posted on November 18th, 2014 PHP Guru No comments

    Quick start

    I recently got a new Macbook Pro (Mavericks) and decided to use the bundled Apache 2.2.6 and PHP 5.4.30.

    All you have to do is uncomment the PHP extension:

    LoadModule php5_module libexec/apache2/

    in /private/etc/apache2/httpd.conf and start Apache:

    sudo apachectl start

    This had me up and running in no time, but after a few days I realized I needed some additional extensions, including MySQL, Mcrypt, Mongo and Redis.

    Brew to the rescue

    There’s no better package manager for Mac OS X than Homebrew (except possibly Macports). So after installing Homebrew:

    ruby -e "$(curl -fsSL"

    I set off to install some additional software and PHP-native extensions:

    brew install redis
    redis-server start
    brew install php54-redis
    ==> Installing php54-redis from homebrew/homebrew-php
    ==> Downloading
    ######################################################################## 100.0%
    ==> PHP_AUTOCONF="/usr/local/opt/autoconf/bin/autoconf" PHP_AUTOHEADER="/usr/local/opt/autoconf/bin/autoheader" /usr/local/Cellar/php54
    ==> ./configure --prefix=/usr/local/Cellar/php54-redis/2.2.5 --with-php-config=/usr/local/Cellar/php54/5.4.33/bin/php-config
    ==> make
    ==> Caveats
    To finish installing redis for PHP 5.4:
    * /usr/local/etc/php/5.4/conf.d/ext-redis.ini was created,
    do not forget to remove it upon extension removal.
    * Validate installation via one of the following methods:
    * Using PHP from a webserver:
    * - Restart your webserver.
    * - Write a PHP page that calls "phpinfo();"
    * - Load it in a browser and look for the info on the redis module.
    * - If you see it, you have been successful!
    * Using PHP from the command line:
    * - Run "php -i" (command-line "phpinfo()")
    * - Look for the info on the redis module.
    * - If you see it, you have been successful!
    ==> Summary
    (beer) /usr/local/Cellar/php54-redis/2.2.5: 3 files, 216K, built in 9 seconds

    Okay, now I should be able to use Redis commands (PHPRedis) in PHP, right?

    Wrong! Whoops:

    sudo apachectl restart

    How about now?


    php -i | grep redis

    Nope, phpinfo() doesn’t show it.

    php -m | grep redis

    Nada; no Redis extension. Rat’s why didn’t that work?


    Let’s look back at the output from the brew php54-redis installer. This part in particular:

    * /usr/local/etc/php/5.4/conf.d/ext-redis.ini was created,

    So, what gives? That seems pretty legit. At least for an Apache & PHP config installed by Homebrew.

    Oh, right, we didn’t do that.

    Here’s the problem: That’s not where Apple’s default PHP build is configured to load extra parsed ini files from.

    That path, by default, is:


    To make the situation even more confusing, that path doesn’t even exist! And, it doesn’t even exist in any config file! It’s actually supplied as an argument (by someone at Apple who worked on the Mac OS X Mavericks Rom supplied to the Macbook Pro factory) when building the PHP binary:

    Configure Command => ... '--with-config-file-scan-dir=/Library/Server/Web/Config/php' ...

    which means we can’t even alter it without re-compiling PHP. Not that we couldn’t, but we don’t need to. Here’s why…

    Symlinks for fun and profit

    All we need to do is get the ini files created by homebrew installers to be loaded by the built-in Apache/PHP that ships with Apple and we are good to go.

    Create this lame, un-changeable non-existent directory tree (-p is recursive; go figure):

    sudo mkdir -p /Library/Server/Web/Config/php

    Next, symlink in there the redis.ini

    sudo ln -s /usr/local/etc/php/5.4/conf.d/ext-redis.ini /Library/Server/Web/Config/php/redis.ini

    Finally, restart Apache

    sudo apachectl restart

    Did that work?

    php -m | grep redis

    Yep, I take that as a good sign.

    All future installs of PHP extensions can be sudo symlinked into this same config-file-scan-dir and we’re good to go.

  • How to fix WordPress wp-admin htpasswd redirect loop

    Posted on August 6th, 2014 phpguru No comments

    If you want a quick and easy way to boost the security of your WordPress blogs, a simple, fast and easy thing you can do is to place a password on your wp-admin directory. CPanel enables this in a moment, just by going to the “Password Protect Directories” feature within CPanel.

    Password protecting directories works following these simple steps.

    1. Click Password Protect Directories
    2. Navigate to public_html by clicking on the folder ICON
    3. Click the folder name link (NOT the icon) for wp-admin directory
    4. In the dialog, enter a username and password and save the details under the User portion
    5. In the dialog, choose to Enable Protection and give it a name, like ‘Top Secret – No Entry’
    6. Save it and then in another browser tab, navigate to

    Now if you’re like me, your wp-admin is broken with a message, “The page has caused a redirect loop”

    You google something like wp-admin htpasswd redirect loop, and find suggestions how to fix it… and find some blog posts like this or that, but you ask your web host about it, and they don’t let you modify httpd.conf config file.

    What to do?

    It turns out the answer is simple, you just need to edit your .htaccess file and add the following line at the top.

    ErrorDocument 401 default

    If you followed the steps above, the CPanel interface created an .htaccess file for you automatically. Go to the file editor feature within CPanel now, and find this new file inside the wp-admin directory, and click edit. Paste the line at the top, save it, refresh wp-admin, and you should be now seeing a dialog asking for your username and password — the one you set at step 4 above. The final .htaccess file including the password protection we added should look like this when you’re done:

    ErrorDocument 401 default
    AuthType Basic
    AuthName "Top Secret - No Entry"
    AuthUserFile "/home/yourusername/.htpasswds/public_html/wp-admin/passwd"
    require valid-user

    Note, do not edit the path for the AuthUserFile – it will be unique to your account and CPanel configuration. This adds a 2nd layer of protection in front of your wp-admin directory in addition to your existing WordPress administrator username and password.

  • How to fix: The connection has timed out in Firefox 29

    Posted on June 6th, 2014 phpguru No comments

    If your web page dies in 5 minutes, it may not be a server-side issue

    I recently ran into a situation where a long-running webpage would timeout after 5 minutes in Firefox. Every time, with no server logs generated.

    I tried increasing the max_execution_time PHP configuration value with ini_set. That didn’t work. I tried set_time_limit() too, but to no avail.

    After a whole lot of debugging PHP on the server side, I discovered the problem was not related to any timeout on the server configuration. The timeout problem results from a new invisible configuration value that was implemented in Firefox itself at version 29. If you’re running Firefox 28 or before, then there was no such default.

    I tried it in Chrome and things worked fine.

    If you use Firefox, please check your version. If you’re on version 29 then Firefox itself can be the culprit generating a timeout error. You might see, “Sorry, the page could not be displayed.” Try again in a few minutes, check your proxy settings, and so on.

    To fix it:

    1. Quit and restart Firefox so only one tab is open.
    2. Go to about:config (type that into the address bar) and then click OK when you are warned that you are about to void your warranty.
    3. Navigate to the following config key: Network -> http -> request -> timeout
    4. and double click on 300
    5. Change it to a larger value, such as 3600 (1 hour), 7200 (2 hours), or 86400 (24 hours) – the value that works best for your application.

    As you can see, the default timeout in Firefox 29 is 300 seconds, or 5 minutes.

    See the accepted answer on for the gory details.

  • How to split a file into 2 chunks in bash

    Posted on May 9th, 2014 phpguru No comments

    I have a task to take a file with millions of lines, and to split it in exactly two files, with a controlled top `head` portion part A file, and the remainder of the lines in part B file.

    It actually turns out to be somewhat non-trival to split a file in 2 chunks, with a small defined top portion and a large arbitrary bottom portion.

    The split [OPTION]... [INPUT [PREFIX]] function is really designed to make N chunks out of your file, or M chunks each containing N lines; I debated using it and merging all but the first file back together, but decided to look up sed examples instead.

    I ended up with the below function. There’s almost certainly a faster/better way to achieve it but this seems to work.

    Sample usage

    remainderof bigfile.txt 1000
    When that runs you will have this result

    1000_bigfile.txt // this is the top 1000 lines
    1000R_bigfile.txt // this is the remainder of the file after splitting off the top 1000 lines
    bigfile.txt // the original untouched file

    Using optional 3rd argument

    remainderof bigfile.txt 1000 true
    When that runs you will have this result

    1000_bigfile.txt // this is the top 1000 lines
    bigfile.txt // this is the remainder of the file after splitting off the top 1000 lines
    // the original file no longer exists

    Here’s the function

    alias ll='ls -larth'
    function remainderof() {
            if [ ! -z $3 ]
            : # $1 was given
            : # $1 was not given
        if [ $# -lt 2 ]
             echo "Usage: $0 filename_to_split rows_to_chop [opt_bool_process_in_place_destructively]"
             exit 1
        length=$( wc -l < $thefile )
        echo Splitting $batchsize lines off the top of $filename $extension leaving $buffer from $length  ...
        #  The top chunk filename
        # The bottom chunk = remainder of file
        echo "Writing $topfile and $remainder"
        # Split off the first N lines of the file
        head -n $batchsize $thefile > $topfile
        # split off the bottom LENGTH - N lines of the file
        sed "1,${batchsize}d" $thefile > $remainder
        # whether to leave a copy
        if [ "$replaceoriginal" = true ] ; then
            rm -rf $thefile
            mv $remainder $thefile
        echo `wc -l < $topfile` lines in $topfile
        echo `wc -l < $remainder` lines in $remainder
        echo Done

    If you have improvements, leave a comment!

  • how to track multiple svn branches in git

    Posted on March 3rd, 2014 phpguru No comments

    [Note: This mirrored blog post was originally online at If you know Bart, link him here so I can update this citation.]

    I must say that I am no fan of SVN, but SVN and I get a long a lot better since I started using git-svn. Long ago a good friend of mine, Dave O’Neill, taught me how to handle multiple branches using git-svn. I had used that technique until Dave taught me how to do it better.

    Recently I saw this blog post which referenced Dave’s article talking about the first method. I guess Dave never got around to updating his blog with the better way. So I am going to do that here:

    A few of my clients use SVN. Some I am guilty of introducing to SVN. But for this post I need to give you an example that you can follow along with. So let’s use shell-fm — my favorite client — with an SVN repo located at svn://

    NOTE: You should use a modern git release. If git --version is older then 1.5.3, you need to upgrade.

    Let’s start by cloning this repository using git-svn:

        $ git svn clone svn:// -T trunk -b branches -t tags

    NOTE: if you have commit access you may want to modify your svn:// url appropriately.

    UPDATE: --stdlayout is a short form for -T trunk -b branches -t tags, and new versions of git-svn support it.

    This process will take longer then an svn checkout would… a lot longer. There are two reasons for this. (1) you are getting all the history of the project, and (2) SVN has a very slow protocol for this purpose.

    Anyway, once it’s done (it took me about 5 minutes) you will have a directory called shell-fm with the contents of trunk checked out in it. If not for the fact that the .svndirectory is replaced with a .git directory you would have thought that you were using a slower SVN.

    Enter into your new repository and you will see that you have a master branch that is, by default, following trunk.

        $ git branch
        * master

    This is not a git tutorial or a git svn tutorial; but I should at least show how to update your tree, and commit to upstream.

    I would like to insert here an advanced topic of packing your repository. I don’t want to explain it here, see the [man page], but trust me it will make your git experience much more enjoyable if you run the following once in a while:

        $ git gc

    Now, to update your working tree to the latest of the branch you are currently tracking, you would run:

        $ git svn rebase

    This is similar to svn update. There are likely no updates available now, so this will do nothing.

    Next, if you want to share something with the upstream svn server you would run:

        $ vim source/main.c
        $ git commit -m"this is a test" source/main.c
        $ git svn dcommit

    This is similar to svn commit.

    Now, let’s look at these branches I was promising:

        $ git branch -r

    Each of the above is tracking a remote branch in SVN, except for trunk which is tracking trunk. When you run git svn fetch all branches will be updated, and new branches on the remote will be added. git svn fetch fetches the updates with out modifying the local working files (which git svn rebase would). git svn fetch mimics standard git fetch behaviour with an upstream git server.

    Working off remote branches is usually done on local topic branches — that is to say, not on master — but you can use whatever you want as git-svn doesn’t care.

    Let’s thus create a new branch for fixing a mythical bug on the 1.2 branch.

        $ git checkout -b fixing-bad-1.2-bug 1.2

    Almost immediately, and without server interaction, we get a checkout of branch 1.2 contents. You can see where you are with:

        $ git branch
        * fixing-bad-1.2-bug

    If you carefully inspect output of git log you can see that git-svn reveals the branch name and upstream SVN commit ID on the last line of each commit:

        $ git log -1
        commit 308244b0d275db460e3b4527afd51258cece4d33
        Author: strogg <strogg@7df44517-d413-0410-91cf-82ca28b36b55>
        Date:   Thu Sep 13 19:39:51 2007 +0000
            This is a patch from Wisq to make shell-fm accept 302 redirects as well as 301.
            git-svn-id: svn:// 7df44517-d413-0410-91cf-82ca28b36b55

    We are on branches/1.2 commit id 252. If you prefer it, you can even get the svn style log output with git svn log… but why?

    Working on this branch is as easy as working off trunk. You edit, commit, and git svn dcommit to upstream.

    Switching between your local branches is easy…

        $ git checkout -f master
        $ hack hack hack
        $ git commit
        $ git checkout -f fixing-bad-1.2-bug
        # and we're back on 1.2 bug fixing

    Note that you don’t have to push your commits back to upstream immediately, or ever for that matter, to make use of the git repository to store your local changes. But if you do decide to you just need to run git svn dcommit.

    If you’re interesting in migrating CVS to git, have a look at the CVS to git Transition Guide.


  • How to prevent iPhoto launching when connecting iPhone

    Posted on August 25th, 2013 phpguru No comments

    The solution is on the Apple forums:

    1. Plug in your iPhone.
    2. Launch Image Capture from your Applications folder
    3. Select your iPhone once it shows up under devices
    4. Look at the lower bottom pane where you’ll see “Connecting this iPhone opens”
    5. Set this preference to “No application”


    See also: How to prevent iTunes from launching when connecting your iPhone or iPad

  • How to prevent iTunes launching when connecting iPhone

    Posted on August 25th, 2013 phpguru No comments

    The solution is on the Apple forums:

    1. From the iTunes menu at the top go to iTunes>Preferences>Devices>Prevent iPods, iPhones and iPads from syncing automatically.
    2. Check the box at the bottom of that window.
    3. Click on [Your Phone's Button] to access the device. This is on the right side of the iTunes main window toward the top, just to the left of the store button. If you don’t see your phone here, unplug it, plug it in again.
    4. Scroll down and uncheck Automatically Sync when this iPhone is connected
    5. Click Done
    6. Quit iTunes.
    7. Unplug and re-plug in your phone. iTunes should not launch.

    If that doesn’t work, also try:

    1. See if iTunes Helper is in System Preferences > Users & Groups > Login Items
    2. If so, delete it (click it then press the minus button)


    See also: How to prevent iPhoto from launching when you connect your iPhone


  • Speak out while Free Speech is Still Free

    Posted on August 2nd, 2013 phpguru No comments

    You may have seen a bumper sticker that says in bold, red, white and blue letters: “Free Speech Isn’t Free.” This short quote cleverly refers to is the fact that millions of courageous U.S. soldiers over more than two centuries have died, that is, paid with their lives, to protect this inalienable right. The analogy works, so long as you value free speech and understand the history of America.

    Dozens of foreign countries, most notably China, Iran and most Islamist-rule nations have a strict policy prohibiting speech and even ideas opposing the government, its leaders, policies or practices. Just glance for a moment at a few of the Chinese dissidents (paying close attention to how long some of them have been detained) if you need a little help imagining what it might be like living under an oppressive regime lacking first-amendment-type protections.

    Practically anyone who’s made it past the 10th grade should be able to recall that the first amendment to the U.S. Constitution guarantees each citizen’s right to free speech, but how many of us actually exercise it today?

    The full text of the amendment protects more than just speech, but here are the specific parts that apply to free speech:

    Congress shall make no law … abridging the freedom of speech, or of the press; or the right of the people peaceably to assemble, and to petition the Government for a redress of grievances.

    Clearly, Congress hasn’t passed any law abridging free speech. However, under the soft tyranny of the Obama administration, free speech is just one of many rights being slowly and methodically stripped away from We The People.

    In a recent speech on the House floor, Congressman Jim Bridenstein, gives us a succinct summary of current events:

    “The President’s Attorney General authorized spying on a Fox News journalist, and his family, for reporting on a North Korean nuclear test. The President’s Justice Department confiscated phone records of the Associated Press because they reported on a thwarted terrorist attack. The President’s Treasury Department uses the IRS to target political opposition.

    This doesn’t sound very American, does it? How about another example: who can forget the infamous YouTube video, which Obama himself, Hillary Clinton and Susan Rice all claimed in their worldwide “explanation” tour, was to blame for violence that led to the deaths of four brave Americans, including Ambassador Chris Stevens, in Benghazi, Libya?

    Even though most of us now believe that the video had nothing to do with the attack in Benghazi, the filmmaker who produced it, Nakoula Basseley Nakoula, remains jailed today. Sure, he wrote some bad checks and violated his parole, but many pundits argue that Nakoula is the Benghazi Patsy, and wouldn’t be in jail today if he hadn’t made the video.

    Are we free to upload original videos to YouTube or aren’t we? Doesn’t the first amendment protect Nakoula, along with Fox’s James Rosen and all those AP reporters trying to get their stories published? More importantly, shouldn’t our President be defending these patriots’ voices, instead of trying to squelch them?

    These stories sound more like they originated in Iran or China than most folks would like to admit, but it’s clear to anyone paying attention to conservative news outlets that the bureaucrats in power are now using federal agencies – when and how they please – against American citizens; actions that are largely unprecedented in modern American political times.

    Should we speak out if we disagree with our government? Many of us are afraid to be accused of offensive ideas, or placing our families or employees in a position to be audited.

    In his famous “Give Me Liberty or Give Me Death” speech in 1775, Patrick Henry asked, and then answered, this very question:

    “Should I keep back my opinions at such a time, through fear of giving offense? I should consider myself as guilty of treason towards my country, and of an act of disloyalty toward the majesty of heaven, which I revere above all earthly kings.

    It’s interesting to note Henry’s comment about earthly kings. In many ways, it can be argued that President Obama has crowned himself King of America, and many conservatives point out that his actions amount to thumbing his nose at the Constitution, instead of protecting and upholding it, as his oath of office requires.

    As we watch these elected officials in D.C. trample our Constitution and run roughshod over the Bill of Rights, keep in mind that you have a duty to yourself, to your family, to your neighbors and to all the soldiers who have died before us. Exercise your first amendment right to call out these leaders, whether they be local, state or federal officials, when, in violation of their oaths, their actions don’t hold true to the America our founding fathers imagined.