$Id: php.txt 1889 2008-08-18 21:46:56Z mjs $
Install, via port, libxml2, libxslt, libiconv, gd2, freetype, sqlite3.
Once these are installed, configure with (adjust as appropriate if ports are not installed into /Ports):
$ ./configure --prefix=$HOME/workspace/beebo/php \
--enable-fastcgi --with-xsl=/Ports --with-libxml-dir=/Ports \
--with-gd=/Ports --with-jpeg-dir=/Ports --with-pdo-sqlite=/Ports \
--without-sqlite --with-freetype-dir=/Ports --with-ttf=/Ports \
--enable-calendar --with-zlib=/Ports --with-iconv --with-openssl \
--enable-discard-path --with-mysql=$LOCAL --with-pdo-mysql=$LOCAL \
--enable-bcmath --with-curl
$LOCAL is where the MySQL libraries and header files are installed. (e.g.
/usr--you can't install MySQL into separate "binary" and "shared"
directories.)
You may want to add --without-pear if PEAR is installed separately and/or
this build doesn't require it.
You can also drop the --without-sqlite to use the bundled
sqlite3. (In this case you also don't need to install sqlite3 via
port.)
The directory specified by --prefix determines where PHP is installed. The
php and php-cgi binaries can be safely moved to other locations, however a
few scripts have this location hardcoded, and won't work if the binaries are
moved (phpize, pear).
--enable-discard-path supposedly eliminates a security
problem.
--enable-bcmath is needed for the Zend OpenId library.
--with-curl provides curl support, which is used by the Zend HTTP Client (I think).
(If compiling with some versions of OS X (10.5.0 and 10.5.4 seem to be affected, at least, replace /usr/include/iconv.h with
MacPorts' version before configuring, to prevent iconv link errors.)
$ make
$ make install
Link php-cgi.dSYM to php-cgi, and php.dSYM to php (DON'T FORGET
THIS!) and strip the binaries.
Then, in your .htaccess or httpd.conf file, arrange for .php files to
be run through the php-cgi via FastCGI:
AddHandler fastcgi-script fcgi
Action application/php-fastcgi /bin/boom.fcgi
AddType application/php-fastcgi .php
Where /bin/boom.fcgi (bin is a subdirectory of document root, not the
filesystem root!) is:
PHP=/Users/mjs/local/php/bin/php-cgi
INCLUDE_PATH=`pwd -L`/../../lib
PHPINI=`pwd -L`/../../etc/php.ini
exec $PHP -c $PHPINI -d include_path=$INCLUDE_PATH
Install the likely module suspects--libjpeg62-dev, libmysqlclient15-dev, libxslt1-dev, libcurl4-openssl-dev, libssl-dev, libsqlite3-dev, libgd2-noxpm, etc.--then configure with:
$ ./configure --prefix=$HOME/beebo.org/php \
--enable-fastcgi --with-xsl=/usr --with-libxml-dir=/usr \
--with-gd --with-pdo-sqlite=/usr --without-sqlite \
--with-freetype-dir=/usr --with-ttf=/usr --enable-calendar \
--with-zlib --with-iconv --with-openssl --enable-discard-path \
--with-jpeg-dir=/usr/lib --with-png-dir=/usr/lib --with-mysql \
--with-pdo-mysql \
--enable-bcmath # for Zend OpenId library
--with-curl # for curl support
You may want to add --without-pear if PEAR is installed separately and/or
this build doesn't require it.
Note that for some reason the JPEG and PNG directory parameters specify the location of their respective libraries, not the root. (I don't know why either of these is necessary; for some reason the bundled GD doesn't come with JPEG and PNG libraries.)
strip the binaries.
Install libxml2, libxslt, gd, libjpeg, libpng, zlib (configure zlib with --shared, otherwise you'll get link errors), then:
$ lconfigure --with-apxs2=$LOCAL/bin/apxs \
--with-xsl=$LOCAL --with-libxml-dir=$LOCAL --with-gd=$LOCAL \
--with-jpeg-dir=$LOCAL --with-png-dir=$LOCAL --with-zlib-dir=$LOCAL \
--enable-debug --with-mysql=/usr/local/mysql --enable-calendar
(Might also need to ln -s $HOME/local/include to $LOCAL/include--one
of the dependencies couldn't find the include files from the
architecture-independent directory.)
Install libxml2, libxslt, then:
$ lconfigure --enable-fastcgi --with-xsl=$LOCAL \
--with-libxml-dir=$LOCAL --with-gd --with-ttf=/usr \
--with-freetype-dir=/usr --enable-calendar
(Uses their gd, ttf, freetype, etc.)
To install:
$ make install
Stripping the binary will save a lot of memory (optional):
$ strip `which php`
Note that this doesn't install the full command-line version (cli). To get that you need to
$ make install-cli
however the command-line version has the same filename--this installs a new "php" binary over the top of your old one. (? I think this changed around 5.2.3.)
To get Dreamhost's Apache to run your php under FastCGI, you need
these lines in your .htaccess:
# Remove the default action for *.php files.
RemoveHandler php
# For some reason the following really does need to be called
# dispatch.fcgi. The contents of dispatch.fcgi:
#
# #!/usr/bin/env bash
#
# exec ./php
#
# DOCUMENT_ROOT/cgi is symlinked to $LOCAL/bin. Dreamhost's config
# seems to have already configured fastcgi-script for *.fcgi.
Action php-fastcgi /cgi/dispatch.fcgi
AddType php-fastcgi html
AddType php-fastcgi php
Get Apache running first.
Download the "ZIP package".
Add something like the following to httpd.conf:
LoadModule php5module "C:/server/php-5.2.4/php5apache22.dll" PHPIniDir "c:/server/php-5.2.4"
(Probably:) Copy php.ini-recommended to php.ini, and tweak as required. (If enabling modules, be sure to set extension_dir!)
Add your PHP directory to PATH, so that various supporting DLLs (e.g. libmysql.dll, libeay32.dll) can be loaded automatically. (How to modify the PATH.)
(optional) Install the Zend debugger
i. Download site. (The "cygwin_nt-i386" version works fine with the regular Windows binaries.)
i. Put the ZendDebugger.dll from the 52x_comp (thread-safe) directory into your PHP extensions directory. (Probably C:\server\php-5.2.4\ext.)
i. Modify php.ini, as described in the README.txt.
i. Restart Apache. A phpinfo() call should mention the debugger.
i. (After all this, couldn't get breakpoints working.)
(optional) Install the Xdebug debugger
i. Download site.
i. Put the php_xdebug-2.0.0-5.2.2.dll into the PHP extensions directory. (Probably C:\server\php-5.2.4\ext.)
i. Add the following to php.ini:
zend_extension_ts=c:/server/php-5.2.4/ext/php_xdebug-2.0.0-5.2.2.dll
xdebug.remote_enable = On
xdebug.remote_host=10.171.99.124
i. Restart Apache. A phpinfo() call should mention the debugger.
i. More info
http://php.net/reserved.variables
Use "." for concatenation; see the PHP manual for more.
Use "break".
http://php.net/manual/en/language.control-structures.php
Includes the alternative syntax.
if (!preg_match("/^foo/", "some string")) {
# ...
}
This doesn't work in PHP:
$sth = odbc_prepare($dbh, $sql);
foreach (...) {
$res = odbc_execute($sth, $arg);
...
}
(The prepared statement gets mashed somewhere--move the odbc_prepare()
into the loop...)
True! You need to use PDO.
i.e. the equivalent of PERL5LIB, PYTHONPATH,
RUBYLIB, etc.:
$ php -d include_path=$PHPLIB
This doesn't seem to be possible in PHP; the best way is to do something like:
Foo::$bar = "hullo, world"!;
class Foo {
public static $bar;
}
class Foo {
static $bar = null;
function quux() {
return self::$bar;
}
}
Give the variable a name that ends in "[]". If there are multiple keys with the same value, and the keys end in "[]", PHP creates an array of values for that value. i.e. if the HTML looks like
<select multiple name="beer[]">
<option value="warthog">Warthog</option>
<option value="guinness">Guinness</option>
<option value="stuttgarter">Stuttgarter</option>
</select>
and the user selects multiple beers, then
gettype($_REQUEST["beer"]) == "array"
See:
http://www.php.net/variables.external
Use call_user_func_array():
call_user_func_array("foo", array(1, 2, 3));
Note that this can also be used to call a method:
call_user_func_array(array($obj, $method), array(1, 2, 3));
date("Y-m-d H:i:s")
If you need to convert e.g. ’ to ’ do something like:
$table = array(
'Á' => 'Á',
'á' => 'á',
...
);
$s = strtr($s, $table);
The Wikipedia source contains an entity conversion table.
@ as a prefix suppresses any warning or error that might otherwise be
emitted.
Note that this works with both method calls and assignments:
$res = @$doc->loadXML($string);
$foo = @$GET_["foo"];
(Other error handling functions.)
I can't figure out how to do this! The closest I can get to is:
$utf32 = iconv("UTF-8", "UTF-32BE", $utf8);
foreach (unpack("N*", $utf32) as $c) {
$xml .= sprintf("&#%d;", $c);
}
which produces a string where every character is expressed as a numeric entity.
error_log() quotes backlashesecho("\\hello\\") -> \hello\
error_log("\\hello\\") -> \\hello\\
odbc_execute($sth, $a);
If any of the element of $a begin and end with a single quote, the bit
in between is interpreted as a filename, the contents of which are
inserted.
Very strange arguments in php.ini:
; Define the probability that the 'garbage collection' process is started
; on every session initialization.
; The probability is calculated by using gc_probability/gc_divisor,
; e.g. 1/100 means there is a 1% chance that the GC process starts
; on each request.
session.gc_probability = 1
session.gc_divisor = 1000
Include is a "special language construct", which means that these two things are not equivalent:
if ($condition)
include $this;
else
include $that;
and
if ($condition) {
include $this;
} else {
include $that;
}
array_filter() and array_map() take their arguments in opposite order:
array array_filter ( array input [, callback callback] )
array array_map ( callback callback, array arr1 [, array ...] )
imageepsbbox returns an array of four values giving the bottom left
and top right coordinates of a given string.
imagettfbbox returns an array of eight values, giving the coordinates
of all four corners of a given string.
parse_str() parses--guess what?--a query string. (Also, the inverse
is http_build_query().)
More unfortunately-named pairs:
htmlspecialchars()/htmlspecialchars_decode()
htmlentities()/html_entity_decode()
The insanity of:
isset($foo)
empty($foo)
is_null($foo)
$foo
(Could possibly add array_key_exists() and defined() to this list too.)
Note also that empty(trim($foo)) doesn't work--the argument to empty()
needs to be a variable, not an expression.
See also:
http://php.net/types.comparisons
include() is relative to the original file, not the included file.
See:
http://bugs.php.net/bug.php?id=9673
You can include() relative to the included file with:
include(dirname(__FILENAME__) . "/../$filename");
Like this:
echo "This works: {$obj->values[3]->name}";
See:
http://php.net/manual/en/language.types.string.php#language.types.string.parsing.complex
parent::__construct(...);
Comment describing how to extend PDOStatement (not tested).
The operators "+", "-" and "." have the same precedence. This means that e.g.
error_log("elapsed time = " . $t1 - $t0)
doesn't do what you expect--it evaluates as
error_log(("elapsed time = " . $t1) - $t0)
(This is the same as Perl.)
(The full operator precedence table. Note the Perl-like low precedence "and", "xor", "or".)
parse_ini_file() returns unexpected results"true", "on", "yes", "1" are converted to "1" (the number 1, as a string).
"false", "off", "no" are converted to "" (the empty string).
"0" is not converted, and is returned as "0" (the number 0, as a string).
Because of this behaviour, and the way values are compared, when
checking for a boolean value via parse_ini_file() (i.e. whether some
setting is true or false), you should simply use if ($value) { ... }
instead of trying to be clever with if ($value == true) { ... },
etc.
$data = array(array(), array());
print_r($data);
foreach ($data as $d) {
$d[0] = "qqq";
}
print_r($data);
0.0 !== 0
0.0 == 0, but 0.0 !== 0. For some reason this isn't listed in the type
comparison table.
print_r(), var_export() and the like output a line per key => value
pair. If you want a few key => value pairs per line, try something
like the following ($table is the original array):
$a = array();
foreach ($table as $k => $v) {
$a[] = sprintf("%11s => %9s,", "'{$k}'", "'{$v}'");
}
for ($i = 0; $i < count($a); $i++) {
echo $a[$i], " ";
if (($i + 1) % 5 === 0) {
echo "\n";
}
}
(Quick hack, doesn't handle ' in either the key or value, for example.)
__call() within functionsThis doesn't work, and is a bug, at least as of PHP 5.2.5.
It can be fixed by applying a patch and re-compiling.
This happens if you're building with XSL (--with-xsl) and libgcrypt
isn't available. You need to install both libgcrypt and its
dependency libgpg-error:
(Or add --without-xsl to your ./configure line.)
(Followed by "The specified module could not be found", and where XXX actually exists.)
PHP seems to produce this error fairly indiscriminately if the module can't
be loaded for any reason at all, not just in the case where the apparently
missing module doesn't exist on the filesystem. For example, it can happen
if you neglect to include a dependency of the named module, such as if you
load php_pdo_oci.dll without loading php_pdo.dll.
It can also happen if an external dependency can't be found (database
DLLs?) or the wrong version is being found (Apache DLLs? Windows
DLLs?). (The PATH is searched for DLLs, but DLLs can come from other
places as well, such as Apache's bin directory.)
If you're having trouble with php_mysql.dll, make sure that
libmySQL.dll can be found.
If you're having trouble with php_pdo_oci.dll, make sure the Oracle
client libraries can be found.
If you're having trouble with php_openssl.dll, make sure libeay32.dll
can be found, and that the wrong version (Apache's?) isn't being
found.
Username and password are specified as follows:
$dbh = new PDO($dsn, $username, $password);
eval() a string as if it were a PHP filei.e. a function like include_string($string) to parallel
include($filename).
eval($string) evaluates $string as if it were PHP code. If you want to
eval a string that looks like a PHP file (i.e. a string that contains
<?php and ?>), do:
function include_string($string) {
eval('?>' . $string . '<?php ');
}
(Astonishing that this works. What is the parser/interpreter doing there?!)
This is documented, somewhat misleadingly, on the eval manpage.
This less than helpful message may be emitted if a pragma command fails.
(You do get slightly more helpful error messages if there's an error in your
SQL proper.) For example, this error will be emitted if you set the charset
to a character set that doesn't exist. To diagnose the problem, it might
help to do a var_dump() on the database handle or statement
handle--sometimes useful information is embedded there.
Despite appearances, the largest file you can upload is affected by several
php.ini settings:
upload_max_filesizepost_max_size memory_limit (possibly)It's possible that since the uploaded file needs to be encoded, which increases their size, these limits need to be larger than you think.
See sapi/cgi/README.FastCGI in the source.
Use the saveXML() method on the associated document:
echo $doc->saveXML($node);
strftime?As far as I can tell, there isn't one.
strtotime,
date_parse or--if you're using
WordPress--mysql2date might do in some circumstances.
Use php://input:
$data = file_get_contents("php://input");
The POSTed data is URL-encoded, so you may need to decode it first:
$data = urldecode(file_get_contents("php://input"));
Zend_Mail with Google Mail's SMTP server$config = array(
'auth' => 'login',
'username' => "XXXX@gmail.com",
'password' => "XXXX",
'ssl' => 'ssl', // not 'tls'
'port' => 465
);
$transport = new ZendMailTransport_Smtp('smtp.gmail.com', $config);
$mail = new Zend_Mail();
$mail->setBodyText('This is the text of the mail.');
$mail->setFrom('sender@test.com', 'Some Sender');
$mail->addTo('mjs@beebo.org', 'Some Recipient');
$mail->setSubject('TestSubject');
$mail->send($transport);
See configuring other mail clients.
Convert an object (i.e. $user->name) to an array (i.e. $user["name"]):
$arr = (array) $obj;
If you have nested objects you'll need to convert it manually:
function object_to_array($obj) {
if (!is_object($obj) && !is_array($obj)) {
return $obj;
}
else {
$a = array();
foreach ($obj as $k => $v) {
$a[$k] = object_to_array($v);
}
return $a;
}
}
file_put_contents("/tmp/log", var_export($foo, true), FILE_APPEND | LOCK_EX);
$a = array();
foreach (debug_backtrace() as $s) {
$a[] = array(
"file" => $s["file"],
"link" => $s["line"]
);
}
rawlog($a);