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 Bookmarks
  • Ping.fm
  • Twitthis

Related posts:

  1. Interactive CLI password prompt in PHP Just a quick tip, since I spent a good hour...
  2. How to Use PHP Namespaces, Part 2: Importing, Aliases, and Name Resolution In the second part of Craig's PHP namespaces series, he...
  3. How to Use PHP Namespaces, Part 3: Keywords and Autoloading In the final part of his series explaining PHP namespaces,...
  4. How to Use PHP Namespaces, Part 1: The Basics In the first part of a series of articles, Craig...
  5. How to Install PHP on Windows In his final installation tutorial, Craig provides a step-by-step guide...

This post has 6 responses so far

Sponsored Links

SitePoint Marketplace

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

Follow SitePoint on...