« February 2009 | Main | April 2009 »

March 31, 2009

Building Forms With interface_functions.php & .skini Files

There are a set of functions for rapidly building web forms to work with the SQL functions. These are found in the common_php/interface_functions.php.

The build_form($form_name, $entity) Function

This is the guts of the interface system and allows you to build web forms quickly and consistently and avoids problems caused by typos in hand coded mark-up.

The function takes a filehandle for a skins/blah.skini file, and a hash to populate the form with values if required. I have avoided doing this however, in favour of using AJAX for populating forms when required instead.

build_form('panel_form');

This will look for and read a file in the skins directory called panel_form.skini and build the form based upon the settings found therein.

The .skini Configuration File Format

These files are in Windows .ini format:


; Each form element should have its own section block.
;
; Sections must be uniquely named as id attributes are assigned 
; based upon them
;
; A 1 means that the section is displayed as a block and 0
; means it is displayed inline. Inline display is trixy and 
; requires extra CSS jiggery pokery more often than not.

[sections]
current_panels = 1
name_section = 1
description_section = 1
location_section = 1
ip_address_section = 1


; For each item under the 'sections' heading there needs to be a 
; separate configuration block.
; 
; The block description should include a label entry (usually label_italic)
; and then the form element included in that section. 


[current_panels]
label_italic = "Edit Existing Panel"
current_panel_id = select_noadd
panel_id = hidden


; If you want to add extra attributes to a form element's tag then 
; you can by defining a section headed as below. This is useful for 
; adding classes, style attributes or JS event handlers:


[current_panel_id]
class = four_c
onchange = "get_panel_details()"

[name_section]
label_italic = "Panel Name"
panel_name = text

[panel_name]
class = four_c

[description_section]
label_italic = "Panel Description"
panel_description = textarea

[panel_description]
class = four_c

[location_section]
label_italic = "Panel Location"
panel_location_id = select_noadd

[panel_location_id]
class = four_c

[ip_address_section]
label_italic = "IP Address"
ip_address = text

[ip_address]
class = four_c

The build_repeating_form($form_name, $entity, $the_count) Function

If you need to build more than one instance of the same form in a single document then you should use this function. This adds the value passed into the third parameter onto the end of all id attributes in the form, separated by an underscore. This is so that we don't duplicate ids.

The get_hour_options() & get_minute_options() Function

To be used along with common_php/option_switcher.php for when you need to choose hours and minutes from <select/> elements.

Posted by pj at 12:51 PM | Comments (0)

Common Header & Footer Includes

All the applications in the framework share the same header and footer with a simple PHP include, although this is not mandatory, but the header sets up all sorts of JavaScripty and CSS goodness required for the framework.

The files are held in the root.

Posted by pj at 11:56 AM | Comments (0)

March 30, 2009

Doing Database "Create Review Update Delete" With Functions In add_update.php

There are a set of functions for abstracting DB CRUD functions in the common_php/add_update_functions.php script.

The add_new_row($table_name) function

This function adds a new row into the table specified, populating only the insert_by and insert_date columns and returning the new primary key value.

The update_table($table_name, $r, $primary_key) Function

This function is for applying updates to individual rows in a table. It is typically used to update a row with the $r / $_REQUEST hash from a form submission. The last argument is the primary key of the row in question, which may have been derived from calling the add_new_row() function.

In the following doozer example code snippet, the same piece of code can be used to either insert a new row or update an existing one depending on whether or not a primary key has been passed in the request:

if(!$r['page_id']){ $r['page_id'] = add_new_row('simple_page'); }

$reply = update_table('simple_page', $r, $r['page_id']);

This function can also be used to delete / expire a row thus:

$reply = update_table('simple_page', array('expired_date' => mktime()), $r['page_id']);

If you want to set a NULL value in a column, for example to undelete / unexpire a row, use:

$reply = update_table('simple_page', array('expired_date' => 'nulled'), $r['page_id']);

This function can also be used to delete / expire a row thus:

$reply = update_table('simple_page', array('expired_date' => mktime()), $r['page_id']);

The update_table_extra($table_name, $r, $where, $primary_key) Function

This function behaves in the same way as the above but allows you to add an extra where clause into the SQL.

$reply = update_table('simple_page', array('expired_date' => mktime()), "page_tags not like '%Public%Document%'", $r['page_id']);

This code expires a particular row in the simple_pages table but only if it hasn't been tagged as a public document.

The date_splitter('publication_date') Function

The interface code returns dates in dd/mm/yyyy format and this needs to be turned into a unix timestamp for storage (date columns should be set as int(20)).

This function takes a date in the $r hash and converts it into a timestamp. The function call is a little unusual in that the function doesn't return anything. So where you have a date in $r['publication_date'] call:

date_spliter('publication_date');
$reply = update_table('my_pages', $r, $page_id);

The call above extracts the date from $r and resets the value with the corresponding timestamp:

function date_splitter($key){

    global $r;

    $b = explode('/', $r[$key]);

    $ts = mktime(0,0,0, $b[1], $b[0], $b[2]);
    
    $r[$key] = $ts;
    
    //print_r($r);
    
    }

The get_options($reply, $value_column, $label_column) Function

This functions more properly belongs in the interface_functions.php file as it is related to form building. Its purpose is to populate <select/> form elements with a list of options.

It takes a reply hash from just_sql() as it's first argument, the second two parameters are the column names you want to map to the value and label of the option respectively. The function can be called like so:

return get_options(just_sql("select * from panel_group where expired_date is null order by panel_group_name"), "panel_group_id", "panel_group_name");

The function is used extensively in option_switcher.php which determines what the option list should be for any <select/> elements in forms generated by build_form($skini_handle).

Posted by pj at 04:05 PM | Comments (0)

Authentication (Login / Logout) & Sessions

Authentication runs of off one table called user and is based upon email address and a password stored as a hash. Once authenticated the user_id from the table is passed around using PHP's $_SESSION variable and relies on cookies.

Sessions are trixy in PHP and you may benefit from referring to the manual - http://uk.php.net/session. You have no real control over the session timeout length for example and currently the user can get unceremoniously dumped out to the login page when the session expires.

The login_doozer.php script handles registration of new users too. This invloves the user being provided with a registration key from the system administrator. If you wish to change your password or have forgotten it, this same mechanism will do the job. Your old row will be expired and a new one created. The system would benefit from an email verification function.

Once you have logged in your user_id from the user table will be used as insert_by and update_by values when doing DB inserts and updates from the system and is encoded in the $user_id variable.

See the login_doozer.php and logout.php scripts in one of the example applications for more details.

For an authenticated script your should include the following lines:

<?
include("paths.inc.php");

session_start();

if(!$_SESSION['user_id']){ header('Location: login.php'); }

$user_id = $_SESSION['user_id'];
................................
?>

Posted by pj at 03:18 PM | Comments (0)

The just_sql() Function & The $reply Hash

The SQL facility for querying the database and getting results back has been abstracted into one function. This presumes that your application has its tables in a single database. If this is not the case you can use the do_sql($db, $sql, $debug) function to specify which db credentials .ini file to use for the query where it is different from the value set in $db_name.

The main function for running a query is just_sql(sprintf("select * from foo where bar = %d", $bar_id)). I tend to use this function in conjunction for sprintf() for extra security.

The $reply Hash

The following code:

$reply = just_sql("select * from equipment where expired_date is null order by update_date desc limit 3");

$rows = $reply['rows'];

header('Content-type: text/plain');

print_r($reply);

produces the following reply hash:

Array
(
    [num_of_rows] => 3
    [rows] => Array
        (
            [0] => Array
                (
                    [equipment_id] => 31
                    [name] => DVD Player
                    [description] => 
                    [insert_by] => 1
                    [insert_date] => 1228746274
                    [update_by] => 1
                    [update_date] => 1228746274
                    [expired_date] => 
                )

            [1] => Array
                (
                    [equipment_id] => 30
                    [name] => Portable Video Conferencing Equipment
                    [description] => 
                    [insert_by] => 1
                    [insert_date] => 1226590805
                    [update_by] => 1
                    [update_date] => 1226590805
                    [expired_date] => 
                )

            [2] => Array
                (
                    [equipment_id] => 29
                    [name] => 7 X PCs
                    [description] => 
                    [insert_by] => 1
                    [insert_date] => 1226327521
                    [update_by] => 1
                    [update_date] => 1226327521
                    [expired_date] => 
                )

        )

    [first_row] => Array
        (
            [equipment_id] => 31
            [name] => DVD Player
            [description] => 
            [insert_by] => 1
            [insert_date] => 1228746274
            [update_by] => 1
            [update_date] => 1228746274
            [expired_date] => 
        )

    [status] => 1
    [message] => OK
    [sql] => select * from equipment where expired_date is null order by update_date desc limit 3
)

N.B. The where clause of the query includes expired_date is null. Every table should have a number of common columns, including an expired_date. This is set with a unix_timestamp() when the row is to be deleted from the DB. In other words, no rows are ever truly deleted, merely expired. You need this test in your where clauses to exclude "deleted" rows.

The result rows are found in $reply['rows'] as a list of hashes. The first row is found in $reply['first_row'] too in case that's all you need. $reply['num_of_rows'] tells you how many rows were returned and the original query SQL is included in $reply['sql'] for easier debugging of dynamic queries.

Posted by pj at 01:52 PM | Comments (0)

The $r / $_REQUEST Shortcut

Each web application built with the framework has its own paths.inc.php file for setting up common variables and paths for the application.

paths.inc.php should be the first include in any application script. One of the roles it performs is to alias the $_REQUEST global variable. A copy of this variable is created and named $r. This is for the sake of pith and saves typing as much as anything else.

$r is used quite extensively in the SQL functions. Elements in application web forms should be named the same as their corresponding DB columns. That way the $_REQUEST/$r hash can then be passed to the SQL functions to do quick and easy inserts and updates such as in the example below for adding a new user:

$userid = add_new_row('user');
        
$r['user_password'] = sha1($r['user_password']);
        
$reply = update_table('user', $r, $userid);

Posted by pj at 12:17 PM | Comments (0)

Getting MySQL-python-1.2.2 to work on Fedora

You need to install mysql-devel:

su
cd 
yum install mysql-devel

Then you need to make sure your /usr/lib/mysql directory is linked under /usr/local/lib

ln -s /usr/lib/mysql /usr/local/lib/.

Now you can install the library

cd MySQL-python-1.2.2
python setup.py install

Posted by pj at 11:29 AM | Comments (0)

March 29, 2009

Getting MySQL-python-1.2.2 to work with XAMPP

I'm trying to get the Python MySQLdb library to talk to my XAMMP MySQL. Here's how:

1. Before you build the db adaptor, change the site.cfg file to point to XAMMP's mysql_config

# The path to mysql_config.
# Only use this if mysql_config is not on your PATH, or you have some weird
# setup that requires it.
mysql_config = /Applications/xampp/xamppfiles/bin/mysql_config

2. Link the dylib

cp /Applications/xampp/xamppfiles/lib/mysql/libmysqlclient.15.dylib /usr/local/mysql/lib/mysql/libmysqlclient_r.15.dylib 

mkdir /Applications/xampp/xamppfiles/include
ln -s /usr/local/mysql-5.1.32-osx10.5-powerpc/include /Applications/xampp/xamppfiles/include/mysql

3. You have to point your script to the localhost using the machines acutally IP address as if it was a remote server.

Posted by pj at 11:59 AM | Comments (0)

CherryPy HTMLTemplate

HTMLTemplate - CherryPy Tools - Trac

Posted by pj at 02:15 AM | Comments (0)

ZPT with CherryPy

ZPT - CherryPy Tools - Trac

svn co svn://svn.zope.org/repos/main/zpkgtools/trunk

Posted by pj at 12:05 AM | Comments (0)

March 28, 2009

Moonlight Mile



Lyrics | The Rolling Stones - Moonlight Mile lyrics

Posted by pj at 12:40 PM | Comments (0)

March 27, 2009

Setting Up Database Connection Credentials With .ini Files

Database credentials are stored in the common_php directory in Windows .ini format files.

[connection_parameters]

user = youruser
password = yourpasswordhere
host = localhost
type = mysql
db = blah

This file should be saved as a .ini file in common_php, and usually with the name of your DB. So for a db named blah, you would name the file blah.ini, and also set $db_name = 'blah'; in your applications paths.inc.php file.

If for extra security you want to name your .ini file something else then that's fine as long as to set $db_name to that.

When the just_sql() function is called it looks for a .ini file named after whatever $db_name is set to, and then parses the contents of that file into a hash to extract the connection credentials and open up a connection before performing the SQL transaction.

The .ini files are protected from view from the webserver using a .htaccess file:

<Files *.ini>
order deny,allow
deny from all
</Files>

Posted by pj at 05:22 PM | Comments (0)

Setting Environment Paths With paths.inc.php

Paths for each individual application are set withing the application directory itself in a file called paths.inc.php.

<?php

$r = $_REQUEST;

global $debug;

$paths = array();

if(file_exists("H:\\xampp\\htdocs\\")){ $docroot = "H:\\xampp\\htdocs\\"; }
if(file_exists("/Applications/xampp/htdocs/")){ $docroot = "/Applications/xampp/htdocs/"; }
if(file_exists("/userdata/home/depts/lis/")){ $docroot ="/userdata/home/depts/lis/"; }

$paths["host"] = $_SERVER["HTTP_HOST"];

$paths["baseref"] = "http://".$paths["host"]."/lis/simple_pages/";

$paths["js"] = "http://".$paths["host"]."/lis/js/";

$paths["js_path"] = $docroot."js/";

$paths["images"] = "http://".$paths["host"]."/lis/images/";

$paths["docroot"] = $docroot;

$config['BaseAddress'] = $paths['baseref'];

$asterix = '<span class="mandatory" style="color: red;">*</span>';

$db_name = 'libfaq';

$user_id = 1;

?>

This should be the first include in any application script:

<?

include("paths.inc.php");

session_start();

if(!$_SESSION['user_id']){ header('Location: login.php'); }

header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); // Date in the past

# Turn off warnings

error_reporting(E_ERROR | E_PARSE);

$debug = false;

$title = "LIS Simple Pages Site - Table of Contents";
.........

The script does several things. Firstly, it creates the $paths hash. Secondly, it aliases $_REQUEST to $r. N.B. If your name any other variable $r things will go bady for you. $r can be used with the add / update functions to add and update rows in a table where the column names match the web form elements.

$booking_id = add_new_row('booking);

$reply = update_table('booking', $r, $booking_id);

The $db_name filehandle is also set here (as opposed to in db_name.inc.php as previously). This refers to the .ini file name stump where your DB settings and credentials are stored. This is usually named after the database itself, but doesn't have to be.

Note also that a default $user_id is set here too. This is important for the add / update functions to work in applications where no user_id is set in the session. Normally this is picked up from the session after login and is the user_id from the user table, in which case this value gets overwritten.

Posted by pj at 11:34 AM | Comments (0)

March 26, 2009

Python script for producing svn diffs


import os

my_file = open('changed_files.txt','r')

lines = my_file.readlines()

for line in lines:

  plode = line.strip()

  els = plode.split('/')
    
  os.popen("svn diff -r 455 " + line.strip() + " > " + "_".join(els) + ".diff")

  print "svn diff -r 455 " + line.strip() + " > " + els[-1] + ".diff"


Posted by pj at 09:31 PM | Comments (0)

.htaccess Tips and Tricks

.HTACCESS files useful tips and tricks

Posted by pj at 08:56 PM | Comments (0)

March 24, 2009

HTML tags you need to know about

10 Rare HTML Tags You Really Should Know - Nettuts

Posted by pj at 03:35 PM | Comments (0)

CherryPy does ZPT

ChoosingATemplatingLanguage - CherryPy - Trac

Posted by pj at 11:14 AM | Comments (0)

March 23, 2009

The common_php directory

The common_php directory contains a number of common function files that need to be included in each script in any application. It includes PHP files with one or more functions related either to the application framework or to individual web applications.

add_update_functions.php
book_request_functions.php
calendar.php
calendar_style.css
check_url.php
cip_functions.php
convert_line_breaks.php
date_parser.php
db_name.inc.php
do_sql.php
email_functions.php
has_value.php
interface_functions.php
is_even.php
kpi_functions.php
libfaq.ini
option_switcher.php
quote_me.php
read_config.php
read_file.php
round_me.php
target_use_attributes.php
upload_file.php
user_functions.php
Framework Specific Files

Posted by pj at 04:43 PM | Comments (0)

File Structure of the Framework

The file structure for the framework is quite shallow. The root includes the following files and folders:

common_php/
js/
skins/
upload_temp/
header.php
footer.php

Posted by pj at 03:54 PM | Comments (0)

Lightweight PHP Web Application Framework - Contents

File Structure of the Framework

Function Include Files in common_php

Setting Environment Paths With paths.inc.php

Setting Up Database Connection Credentials With .ini Files

The $r / $_REQUEST Shortcut

The just_sql() Function & The $reply Hash

Authentication (Login / Logout) & Sessions

Doing Database "Create Review Update Delete" With Functions In add_update.php

Common Header & Footer Includes

Building Forms With interface_functions.php & .skini Files

Populating select Element Option Lists with option_switcher.php

Using the poppy() JavaScript Function For Application Alerting

Using JavaScript Validation For Mandatory Form Elements

Using prototype.js For Faster JS Development and AJAX

Building Application DB Tables with tables.ini and create_database.php

Posted by pj at 03:41 PM | Comments (0)

Google API Translation

Fuzzy Buckets: Translation Tools

Posted by pj at 12:28 AM | Comments (0)

March 18, 2009

Google Language API Docs

Developer's Guide - Google AJAX Language API - Google Code

Posted by pj at 04:59 PM | Comments (0)

March 17, 2009

Dell Mini Running Mac OS X

How To: Hackintosh a Dell Mini 9 Into the Ultimate OS X Netbook

Posted by pj at 11:04 AM | Comments (0)

March 16, 2009

Edinburgh Kung Fu

Yee's Hung Ga Kung Fu Edinburgh - Home

Posted by pj at 11:09 PM | Comments (0)

March 15, 2009

My Jython Regex Servlet

The servlet:

from javax.servlet.http import HttpServlet

import re

import string

class regexTest(HttpServlet):

    def doGet(self,request,response):

        self.doPost (request,response)

    def doPost(self,request,response):
    
        #param_names = request.getParameterNames()

        writer = response.getWriter()

        response.setContentType ("text/plain")
        
        try: expr = request.getParameterValues("expr")[0]

        except:
            
            final_hash = { "errors" : ['']}
            
            final_hash['errors'][0] = 'You must enter an expression.'

            writer.println(final_hash)

            sys.exit

        try: this_text = request.getParameterValues("text")[0]

        except:
            
            final_hash = { "errors" : ['']}
            
            final_hash['errors'][0] = 'You must enter some text.'

            writer.println(final_hash)
            
            sys.exit

        reg = regexTest()

        try: final_hash = reg.test_it(expr, this_text)
        
        except:
            
            final_hash = { "errors" : ['']}
            
            final_hash['errors'][0] = 'Failed to run test.'

            writer.println(final_hash)
            
            sys.exit
        
        #except: writer.println('')
        
        #writer.println('')

        writer.println(final_hash)
        

                
    #def __init__(self, text="Stuff"):
        
    #    self.text = text
        
    def test_it(self, exp, text):
        
        final_hash = {}
        
        try: this_reg = re.compile(exp) 
        
        except:
            
            final_hash['error'] = ['Your expression did not compile'] 
        
            return final_hash
        
        #print this_reg
        
        this_match = this_reg.findall(text)
        
        final_hash["results"] = this_match 
        
        if this_match:
        
            return final_hash
        
        else:
        
            final_hash['error'] = ['Your expression found no matches']
            
            return final_hash

#if __name__ == "__main__":
    
#    reg = regexTest()
    
#    print reg.test_it('[\d]+', 'These are words and phone 07590 574469')


The JSP with the JSON:

<%@ page contentType="text/html" %>
<!-- %@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" % -->
<html>
<head>
    <link rel="stylesheet" href="styles.css" type="text/css" media="all"/>    
    <script type="text/javascript" src="js/prototype.js"></script>
    <script type="text/javascript" src="js/set_date.js"></script>
    <script type="text/javascript">
    function do_regex(){
    
        if(($('text').value == '') || ($('regex').value == '')){ alert('You must enter some text and an expression'); return false; }
    
        var url  = 'regexTest.py';
        var params = '?text=' + escape($('text').value) + '&expr=' + escape($('regex').value);
        var myAjax = new Ajax.Request(
                            url,
                            {
                                    method: 'get',
                                    parameters: params,
                                    onComplete: show_response
                            });
    
        function show_response(this_request){
        
            this_result = this_request.responseText;
        
            $('regex_here').value = this_result;
            
            }

        }

    </script>
    <title>Regular Expression Test Harness</title>
</head>
<body>
<h2 style="margin-left: 1em;">Regex Test Harness</h2>
<form action="#" method="post" style="width: 80%; margin: 2em; border: 1px solid #dcdcdc;">

<p style="margin-left: 1em;">
<label id="text_block_label" class="label_italic">Text
<em class="astrix" id="text_mandatory" style="display: none;">*</em></label>
<br/>
<em id="text_outer">
<input type="text" name="text" id="text"  class="four_c" value=""/>
</em>
</p>

<p style="margin-left: 1em;">
<label id="regex_block_label" class="label_italic">Regex
<em class="astrix" id="regex_mandatory" style="display: none;">*</em></label>
<br/>
<em id="regex_outer">
<input type="regex" name="regex" id="regex"  class="four_c" value="" onblur="do_regex()"/>
</em> <input type="button" value="Go»" class="button" onclick="do_regex()"/>
</p>

<form>
<textarea style="height: 100px; width: 400px; margin: 1em; color: red;" id="regex_here">
</textarea>
</form>

</form>
</body>
</html>

Posted by pj at 10:01 PM | Comments (0)

March 14, 2009

phpPGAdmin

SourceForge Site

Posted by pj at 03:37 PM | Comments (0)

March 12, 2009

BibClassify Keyword Extraction into SKOS RDF

Atlantis Institute of Fictive Science: BibClassify Admin Guide

Posted by pj at 03:10 PM | Comments (0)

March 09, 2009

Getting PyServlet and Jython working

After a couple of days of hairloss I put the following into the container web.xml:

<servlet>
    <servlet-name>PyServlet</servlet-name>
    <servlet-class>org.python.util.PyServlet</servlet-class>
    <param-name>python.home</param-name>
    <param-value>/usr/local/jython</param-value>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>PyServlet</servlet-name>
    <url-pattern>*.py</url-pattern>
</servlet-mapping>

Also I had to link:

/usr/local/jython/Lib to /Library/Tomcat/Home/conf/common/lib/Lib

and do the same for my application lib directory.

Now my jylets work.

Posted by pj at 11:37 AM | Comments (0)

March 07, 2009

Regular Expressions in JavaScript

Regular Expressions in JavaScript | evolt.org

Posted by pj at 10:32 PM | Comments (0)

Jython Webapp Tutorial

Jython Webapp Tutorial - Part 1 - Writing Servlets in Jython

Posted by pj at 03:41 PM | Comments (0)

Mo' Web Hooks

Web Hooks / FrontPage

Posted by pj at 10:19 AM | Comments (0)

What the hell are webhooks?

Web Hooks

Posted by pj at 10:17 AM | Comments (0)

March 05, 2009

XSL for Twitter to RDF

twitter-rdf.xsl at a0ec36781e3af9995a3bccb228e48dd51692b814 from tommorris's twitter-rdf - GitHub

Posted by pj at 09:47 PM | Comments (0)

March 01, 2009

Web Curator Tool

Web Curator Tool

Posted by pj at 08:15 PM | Comments (0)