Blog Post RSS ?

Blogs » PHP » PHP Manual CLI style 2.0
 

PHP Manual CLI style 2.0

by Troels Knak-Nielsen

Harry mentioned the handy little phpm some three 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\).*\n\1/d; s/\n//; h; P' \
        | sed -e '/^# \(.*\)$/ { s/^# \(.*\)/\1/p ; s/\(.\{1,1\}\)/=/g }' -e '/^## \(.*\)$/ { s/^## \(.*\)/\n\1/p ; s/\(.\{1,1\}\)/-/g }' -e '/^### \(.*\)$/ { s/^### \(.*\)/\n\1/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)
Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google
  • Ping.fm
  • TwitThis

This post has 6 responses so far

  1. Just tried. Nice job~~

     
  2. This is the shell-script of the year, and if you are a LAMP developer, the script of the century! Well done Troels, great use of sed :)

     
  3. Somewhere my wget is configured to send an Accept-Language header for german. First the german umlauts were not displayed correctly on my ISO-8859-1 terminal, second I don’t rely on the translated manual pages as there are sometimes outdated. So I changed line 57 to explicitly ask for english pages:

    RESPONSE=$(wget --header='Accept-Language: en' --quiet -O - $HREF)

    Make sure to run phpm --clear after changing!

     
  4. Include it in VIM, using Tobias Schlitt’s config[1]:

    " Map -H to search phpm for the function name currently under the cursor (insert mode only)
    inoremap :!phpm =expand("")

    [1] http://schlitt.info/applications/blog/index.php/plugin/tag/vim

     
  5. Nice script.

    If you are a Windows user who has Microsoft Desktop Search installed, an alternative way to access php help would be to create a shortcut by typing the following in the Desktop Search box:
    @phpm , http://www.php.net/manual-lookup.php?function=$w

    Then you should be able to type in the following to get help:
    phpm substring

     
  6. [...] The installation instructions are available at: http://www.sitepoint.com/blogs/2007/11/28/php-manual-cli-style-20/ [...]

     

Sponsored Links

SitePoint Marketplace

Buy and sell Websites, templates, domain names, hosting, graphics and more.

Follow us on Twitter