PHP preg_replace URL

To search for urls and convert them into html links you may use preg_replace() in PHP. Though writing regular expression might be not very easy. Here is an example of regular expression which will catch and replace urls which may be:

  • in the beginning of string,
  • in the end of string,
  • configurable prefix/suffix delimiter,
  • with configurable scheme.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php
 
// configurable delimiters and schemes
$delimiters = '\\s"\\.\',';
$schemes = 'https?|ftps?';
 
$pattern = sprintf('#(^|[%s])((?:%s)://\\S+[^%1$s])([%1$s]?)#i', $delimiters, $schemes);
$replacement = '$1<a href="$2">$2</a>$3';
 
$subjects = array(
    'http://localhost',
    'https://example.com',
    ' ftp://example.com',
    'ftps://example.com ',
    'prefix http://example.com',
    'http://example.com suffix',
    'prefix http://example.com/path suffix',
    'prefix http://example.com/path&var=val suffix',
    'prefix http://example.com/path&var=val, suffix',
    'prefix http://example.com/path&var=val. suffix',
    'prefix "http://example.com/path&var=val" suffix',
    'prefix \'http://example.com/path&var=val\' suffix',
);
 
foreach ($subjects as $subject) {
    var_dump(preg_replace($pattern, $replacement, $subject));
}

Continuous Integration and development environment approach

PHPDocTester – console script for evaluating your PHPDoc comments

If you are fan of command line like me and do some PHP coding in console or simply keep console constantly opened than this script could be useful for you for quick evaluation of PHPDoc documentation generated for your PHP.

This script will generate PHPDoc documentation saving all files into temporary folder, display them in elinks console web browser and clear temporary folder after leaving browser. Script expects “elinks” and “phpdoc” to be installed on your system.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#!/bin/sh
PATH=/bin:/usr/bin:
 
# check input parameters
if [ "$#" -lt 1 ]; then
    echo "Usage:"
    echo "`basename $0` filename/dirname [options]"
    exit 1
fi
 
# create temporary directory
TARGET=`mktemp -dt phpdoctester.XXXXXX`
FILE=$1
 
# check if input is directory, otherwise assume it's file or filemask
if [ -d "$FILE" ]; then
    FCONFDIR="--directory"
else
    FCONFDIR="--filename"
fi
 
# create phpdoc documentation in temporary directory
phpdoc \
	$FCONFDIR "$FILE" \
	--target "$TARGET" \
	--parseprivate on \
	--undocumentedelements on \
	--output HTML:frames:default \
	|
	grep -P 'ERROR in |WARNING in ' \
	|
	sed -e 's/^\s*\(.*\)/\1/'
 
echo "\nPress any key to open phpdoc in console web browser..."
read
 
# show documentation in console browser
DOCFILE="${TARGET}/index.html"
elinks $DOCFILE 
 
# remove temporary directory
rm -r $TARGET

AJAX-based page update with graceful degradation

This is a simplified POC showing how to use partial page update with AJAX when JavaScript is enabled but still have working website links in case of disabled JavaScript in client browser. It uses a bit of jQuery and PHP scripting.

Go directly to the demonstration. You can safely disable JavaScript in your browser (don’t forget to reload page though after that) and links still will work. You may also copy hash based links (http://www.devhands.com/wp-content/custom/smartlinks/#page3) and insert them into new browser tab, they also will work with enabled JavaScript.
(more…)

Scalable web architecture

Domains whitelist for Exim smarthost

Here is a quick hack for making a whitelist of destination domains for your exim smarthost configuration. It means that emails will be sent only to domains which you explicitly specify.

You may ask why “hack”? Because Exim will send bounce emails which most probably is not what you want, reject could be a better behavior.

Find your Exim configuration file for smarthost, /etc/exim4/exim4.conf.template under Ubuntu. And edit domains configuration parameter specifying colon separated list of allowed destination domains as a value.

domains = domain1.com:domain2.com

If your use Ubuntu update main configuration file by executing update-exim4.conf from command line as root user.

Subversion hook php framework

Subversion provides very powerful hook system which allows extending it with custom logic. Hook is a command line script which is executed on selected repository event receiving metadata as command line arguments and providing results within output and exit code.

With a help of hook script you can validate commit log message or even submitted changes before saving them into repository and notify user if there are any errors.

If you have php on your server with a help of special PHP class your very powerful subversion hook might look like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/usr/bin/php
<?php
require '/var/svn/common-hooks/CommitTests.php';
putenv('PATH=/usr/bin');
 
new CommitTests($argv[1], $argv[2], array(
    'LogMessageLength' => array(3),
    'TabIndents' => array(array('php', 'phtml')),
    'TrailingSpaces' => array(array('php', 'phtml', 'ini')),
    'SvnProperties' => array(array(
        'php' => array('svn:keywords=Revision', 'svn:eol-style=LF'),
        'phtml' => array('svn:keywords=Revision', 'svn:eol-style=LF'),
        'html' => array('svn:eol-style=LF'),
    )),
));

This script have following pre-commit validation rules:

  • Minimum log message length is 3 characters
  • Tab indents are not allowed in *.php and *.phtml files
  • Trailing spaces are not allowed in *.php, *.phtml and *.ini files
  • *.php and *.phtml files should have following svn tags set: svn:keywords=Revision, svn:eol-style=LF
  • *.html files should have svn tag svn:eol-style=LF

Download CommitTests.php file.

Handling positional and non-positional command line arguments from a shell script

When you want to use non-positional command line arguments together with positional you may use getopts to parse non-positional arguments and than use $OPTIND environment variable set by getopts to access positional arguments.

Of course positional arguments should follow non-positional ones. Let’s assume you plan to have following syntax:

script.sh [options] ARG1 ARG2

At first you have to parse non-positional arguments which will be options in this case with getopts:

while getopts "h:u:p:d:" flag; do
case "$flag" in
    h) HOSTNAME=$OPTARG;;
    u) USERNAME=$OPTARG;;
    p) PASSWORD=$OPTARG;;
    d) DATABASE=$OPTARG;;
esac
done

Than you may want to ensure that required positional arguments were passed:

if [ $(( $# - $OPTIND )) -lt 1 ]; then
    echo "Usage: `basename` [options] ARG1 ARG2"
    exit 1
fi

Later you can access positional arguments using array expansion ${@:START:1}:

ARG1=${@:$OPTIND:1}
ARG2=${@:$OPTIND+1:1}

How to get the full path from the running bash script

If you need to get an absolute path of the script folder within the running shell script you may use readlink and dirname commands:

#!/bin/sh
echo $(dirname $(readlink -f $0))

or (credits to kazoolist)

#!/bin/sh
echo $(dirname $(readlink -f ${BASH_SOURCE[0]}))

which will work when script is run using “source”.

PHP 5.3.0 open_basedir bug

If you experience open_basedir restrictions in PHP 5.3.0 while active open_basedir path should allow script execution this is a known PHP bug: Bug #48744 and Bug #48880.

Source of this issue lies in fopen_wrappers.c and is already fixed in svn.

Here is the patch you can safely apply to PHP 5.3.0 sources to fixing this issue:

--- php/php-src/branches/PHP_5_3/main/fopen_wrappers.c	2009/06/18 06:38:30	282359
+++ php/php-src/branches/PHP_5_3/main/fopen_wrappers.c	2009/07/31 21:09:45	286602
@@ -93,7 +93,7 @@
 
 	p = (char **) (base + (size_t) mh_arg1);
 
-	if (stage == PHP_INI_STAGE_STARTUP || stage == PHP_INI_STAGE_SHUTDOWN) {
+	if (stage == PHP_INI_STAGE_STARTUP || stage == PHP_INI_STAGE_SHUTDOWN || stage == PHP_INI_STAGE_ACTIVATE || stage == PHP_INI_STAGE_DEACTIVATE) {
 		/* We're in a PHP_INI_SYSTEM context, no restrictions */
 		*p = new_value;
 		return SUCCESS;