We’ve previously discussed phpm here on SitePoint some years ago. And Sean Coates was kind enough to point out how it could be replaced with a shell one-liner. Doesn’t that just make one love bash?
One thing, I missed with either of the two, was the ability to see the entire manual entry. It’s quite often, that the manual actually holds useful information (Who’d known that!), so I find myself using www.php.net a lot. Or I did, until I decided to do something about it. Now, shell-scripting isn’t what I spent most of my time on, so it’s not with out a bit of pride, that I present to you phpm two-oh.
#!/bin/bash
# phpm
# commandline php-manual interface
# Kudos to Havard Eide and Sean Coates for the original idea
#
# author: Troels Knak-Nielsen <troelskn@gmail.com>
# version: 2007-11-27
#
# dependencies:
# wget sudo apt-get install wget
# sed sudo apt-get install sed
# tidy sudo apt-get install tidy
# xmlstarlet sudo apt-get install xmlstarlet
# konwert sudo apt-get install konwert
# html2text get from http://www.aaronsw.com/2002/html2text/html2text.py
# symlink to ~/bin/html2text
# urlencode get from http://www.shelldorado.de/scripts/cmds/urlencode.txt
# symlink to ~/bin/urlencode
function print_usage {
echo "USAGE: phpm <function>"
echo "To clear cache: phpm --clear"
exit 0
}
# create cachedir on first run
CACHEDIR=~/.phpm
if [ ! -e $CACHEDIR ]
then
mkdir $CACHEDIR
fi
if [ $# -gt 0 ]
then
# parse a few options
if [ $1 = "--clear" ]
then
echo "clearing cache"
rm -r $CACHEDIR
exit 0
fi
if [ $1 = "--help" ]
then
print_usage
fi
if [ $1 = "-?" ]
then
print_usage
fi
URLNAME=$(echo $1 | urlencode)
CACHE_FILENAME=$CACHEDIR/$URLNAME
# check cache
if [ ! -e $CACHE_FILENAME ]
then
# fetch from HTTP
HREF=http://www.php.net/manual-lookup.php?function=$URLNAME
RESPONSE=$(wget --quiet -O - $HREF)
if [ $? != 0 ]
then
echo "HTTP error" 1>&2
exit $?
fi
# process response
# test if function has direct match
if echo $RESPONSE | grep -Eiq '<div([^>]*)class="refentry">'
then
# grap and format output
# the first sed collapses blank lines, the second formats headers
echo $RESPONSE
| tidy -latin1 -asxhtml --input-encoding utf8 --output-xml true --numeric-entities true 2>/dev/null
| xmlstarlet select --net --html -t -c "//*[@class='refentry']" 2>/dev/null
| tidy -latin1 --input-encoding utf8 -asxhtml 2>/dev/null
| konwert utf8-ascii
| html2text 2>&1
| sed -n 'G; s/n/&&/; /^([ -~]*n).*n1/d; s/n//; h; P'
| sed -e '/^# (.*)$/ { s/^# (.*)/1/p ; s/(.{1,1})/=/g }' -e '/^## (.*)$/ { s/^## (.*)/n1/p ; s/(.{1,1})/-/g }' -e '/^### (.*)$/ { s/^### (.*)/n1/p ; s/(.{1,1})/~/g }'
> $CACHE_FILENAME
# test if there are any "best" matches
elif echo $RESPONSE | grep -Eiq '<a href="/manual/en/function[^>]*><b>'
then
echo "Best matches for '$1':" > $CACHE_FILENAME
echo $RESPONSE
| tidy -latin1 -asxhtml --input-encoding utf8 --output-xml true --numeric-entities true --wrap 0 2>/dev/null
| sed -n 's/.*<a href="/manual/en/function[^>]*><b>([^<]{1,})<.*/1/p'
>> $CACHE_FILENAME
# test if there are any "weak" matches
elif echo $RESPONSE | grep -Eiq '<a href="/manual/en/function[^>]*>[^<]+'
then
echo "Possible matches for '$1':" > $CACHE_FILENAME
echo $RESPONSE
| tidy -latin1 -asxhtml --input-encoding utf8 --output-xml true --numeric-entities true --wrap 0 2>/dev/null
| sed -n 's/.*<a href="/manual/en/function[^>]*>[^<]{1,}([^<]{1,})<.*/1/p'
>> $CACHE_FILENAME
fi
fi
if [ -e $CACHE_FILENAME ]
then
cat $CACHE_FILENAME
else
echo "No matches found for '$1'"
exit -1
fi
else
print_usage
fi
Installing it
You obviously need a bash environment to run it (I suppose cygwin will do). Apart from that, you need a host of cli tools and utilities. If you’re on a debian based system, the following should get you running:
sudo apt-get install wget sed tidy xmlstarlet konwert
Then get the following two scripts:
Save them (Without file-extension) in ~/bin
and make them executable:
chmod +x ~/bin/html2text
chmod +x ~/bin/urlencode
(Or you can put them somewhere, such as in ~/scripts
and then symlink them)
Finally, save the above script as ~/bin/phpm
and chmod it, like the other two scripts.
Usage
You should now be able to look up a function in the PHP manual as simple as:
phpm substr
As a bonus, you’ll get a list of suggestions for mismatches. For example:
$ phpm substring
Best matches for 'substring':
is_string
substr
Very handy, when you only remember part of the function name.
The script queries the php website for the documentation, so it’s always up-to-date. To improve performance, results are cached in ~/.phpm
. You can always clear the cache by calling phpm like:
phpm --clear
Emacs bonus
As a final little bonus for the Emacs-users about, here’s a snippet for binding F4 to phpm for the current word:
(defun php-manual-lookup ()
"Shows short documentation for the word at the point."
(interactive)
(let ((word (current-word t))
(buffername "*phpm*"))
(when (get-buffer buffername)
(kill-buffer buffername))
(save-excursion
(pop-to-buffer buffername)
(shell-command (format "phpm %s"
(shell-quote-argument word)) buffername)
(other-window 1))))
(global-set-key '[f4] 'php-manual-lookup)
Troels has been crafting web applications, as a freelancer and while employed by companies of various sizes, since around the time of the IT-bubble burst. Nowadays, he's working on backend systems for a Danish ISP. In his spare time, he develops and maintains Konstrukt, a web application framework for PHP, and is the organizer of a monthly PHP-meetup in Copenhagen.