Rectangle 27 31

You can create a one-way hash with bcrypt using PHP's crypt() function and passing in an appropriate Blowfish salt. The most important of the whole equation is that A) the algorithm hasn't been compromised and B) you properly salt each password. Don't use an application-wide salt; that opens up your entire application to attack from a single set of Rainbow tables.

This is the right approach - use PHP's crypt() function, which supports several different password hashing functions. Make sure you are not using CRYPT_STD_DES or CRYPT_EXT_DES - any of the other supported types are fine (and includes bcrypt, under the name CRYPT_BLOWFISH).

SHA indeed has a cost parameter as well, via the 'rounds' option. When using that, I also see no reason to favour bcrypt.

Actually, a single SHA-1 (or MD5) of a password is still easily brute-force-able, with or without salt (salt helps against rainbow tables, not against brute-forcing). Use bcrypt.

I find it disturbing that everybody seems to say "bcrypt" when they mean php's crypt().

@Panique Why? The algorithm is called bcrypt. crypt exposes several password hashes, with bcrypt corresponding to the CRYPT_BLOWFISH constant. Bcrypt is currently the strongest algorithm supported by crypt and several others it supports are quite weak.

How do you use bcrypt for hashing passwords in PHP? - Stack Overflow

php passwords cryptography password-protection bcrypt
Rectangle 27 31

You can create a one-way hash with bcrypt using PHP's crypt() function and passing in an appropriate Blowfish salt. The most important of the whole equation is that A) the algorithm hasn't been compromised and B) you properly salt each password. Don't use an application-wide salt; that opens up your entire application to attack from a single set of Rainbow tables.

This is the right approach - use PHP's crypt() function, which supports several different password hashing functions. Make sure you are not using CRYPT_STD_DES or CRYPT_EXT_DES - any of the other supported types are fine (and includes bcrypt, under the name CRYPT_BLOWFISH).

SHA indeed has a cost parameter as well, via the 'rounds' option. When using that, I also see no reason to favour bcrypt.

Actually, a single SHA-1 (or MD5) of a password is still easily brute-force-able, with or without salt (salt helps against rainbow tables, not against brute-forcing). Use bcrypt.

I find it disturbing that everybody seems to say "bcrypt" when they mean php's crypt().

@Panique Why? The algorithm is called bcrypt. crypt exposes several password hashes, with bcrypt corresponding to the CRYPT_BLOWFISH constant. Bcrypt is currently the strongest algorithm supported by crypt and several others it supports are quite weak.

How do you use bcrypt for hashing passwords in PHP? - Stack Overflow

php passwords cryptography password-protection bcrypt
Rectangle 27 51

The system allows full access to all PHP functions - no restrictions and no safe mode. Many common extensions are loaded and available for use. Security is provided on an OS level by strict user permissions inside a setuid chroot jail protected by system call tracing, which should all be transparent to PHP code. You can write files in the /temp folder, but they will be periodically deleted.

The Profile code option will use XDebug to trace every function call in your code and measure the time taken, and will also use VLD to generate a full opcode listing to see how PHP executes your code 'under the hood'!

used this for quite a while, and very good, as of this writing, its currently down

still is offline a year later... guess it's safe to say it's not coming back?

Is there a PHP Sandbox, something like JSFiddle is to JS? - Stack Over...

php sandbox
Rectangle 27 2

$export_data = array_replace(array_map(function($v){return null;}, range(0, max(array_keys($export_data)))), $export_data);

Tested 100,000 iterations and results are in seconds:

Version     Run1  Run2  Run3
PHP 5.6.20  .58   .55   .50
PHP 7.0.5   .18   .21   .21

Now for the explanation so I don't get flogged with downvotes or get accused of witchcraft.

$export_data = array (
    0 => 1,
    1 => 2,
    2 => 3,
    3 => 4,
    4 => 5,
    8 => 9,
    9 => 10,
);

$export_data = 
    array_replace( // replace the elements of the 10-item array with your original array and the filled-in blanks are going to be null. I did not use array_merge() because it would append $export_data onto our dynamic range() array rather than replacing elements as needed.
        array_map( // loop the 10-item array and apply the declared function per element. This function ends up returning the 10-item array with all keys intact but the values will be null
            function($v){return null; /* return ''; // if you prefer and empty string instead of null*/}, // set each value of the 10-item array to null
            range( // create an 10-item array with indexes and values of 0-9
                0,
                max(array_keys($export_data)) // get the highest key of your array which is 9
            )
        ),
        $export_data // your original array with gaps
    );

var_dump($export_data);
print_r($export_data);

Thank you really appreciate for your time and response. All the other answers were correct however this does exactly what I needed in one line of code. Also great explanation thanks again.

@user4676307 I'm glad you like it. I was initially considering a similar approach to Jimmmy but wanted to show you the power of all the various PHP functions :-). Good luck with your project!

Witchcraft! :-) i like yours solution, it will be sure quicker than mine on longer arrays (which csv mostly are). +1

@Jimmmy believe it or not but your solution is almost twice as fast as mine, lol. With some minor optimization, it can go even faster.

PHP Export Indexed Array into CSV - Stack Overflow

php csv
Rectangle 27 1

You are getting the "Call to a member function makeup() on a non-object" because $ret is an array and doesnt have a method called "makeup()."

I am not sure exactly all you are trying to do but something like this might get you a little closer. I am assuming you have some function named makeup() that produces a string "< div>":

<?
php include_once '%resource(simple_html_dom.php)%';  
$html = file_get_html('b.html'); 
$ret = $html->find('div[id=testdiv]', 0)->innertext; 
$ret = makeup() . $ret . '</div>'; 

echo $ret; 
?>

Thanks Colin, I saw makeup on another post - thought it was a standard PHP function - I'm going to eliminate that. See Updated code above and final question.

PHP Simple HTML DOM Parser: Insert HTML - Stack Overflow

php dom
Rectangle 27 4

You write that at the time when this problem occurs, you have several clients doing AJAX requests every 3 seconds. This makes it likely that all the PHP workers available at your server are blocked by these AJAX requests. Your web server receives your request for /foobar.php and then has to wait until a PHP worker is free to process your request.

So among the possible solutions for your problem are (without you being more specific what the AJAX is needed for, I need to keep this general):

  • have the AJAX requests go to a static file
  • ensure that PHP really closes the connection when the (AJAX) request is finished, for example with a header("Connection: close"); (though this might not be enough, check the comments on the PHP manual about connection handling)
  • reduce the number of AJAX requests made (to a number worked out in cooperation with your provider)

In general you will need your provider's help with solving this. You did not write which method your provider uses for serving PHP, for example with fpm there is a setting called process.max that can limit your web servers ability to process so many PHP files in parallel.

I already asked this: MaxClients 300, MaxRequestsPerChild 4000, ThreadsPerChild 25.. I would be happy if you can tell me which addtional parameters should I ask to my provider for more information about this problem..

-Making AJAX request is obligatory for me. It is very important for my site to make users easily solve their issues. This requests must point to a PHP function. -"You did not write which method your provider uses for serving PHP" What are the options for this? If you can tell me the alternatives then I can ask to my provider. Do you mean this. -I use jQuery for AJAX requests. So I suppose that jQuery closes the connection after getting the AJAX response.

Yes, I mean something like that. the MaxClients only applies if mod_php is used. If they use fpm then the setting I mentioned above applies.

Thank you. Provider told me that PHP handler is Apache module. So what would I ask more? MaxProcessCount or any other more?

apache - Long Time to First Byte value for an empty php file - Stack O...

php apache .htaccess cakephp mod-php
Rectangle 27 28

This website offers a great guide and code to do this (which was the first result of a Google search for this question):

<?php

/*
 * ip_in_range.php - Function to determine if an IP is located in a
 *                   specific range as specified via several alternative
 *                   formats.
 *
 * Network ranges can be specified as:
 * 1. Wildcard format:     1.2.3.*
 * 2. CIDR format:         1.2.3/24  OR  1.2.3.4/255.255.255.0
 * 3. Start-End IP format: 1.2.3.0-1.2.3.255
 *
 * Return value BOOLEAN : ip_in_range($ip, $range);
 *
 * Copyright 2008: Paul Gregg <pgregg@pgregg.com>
 * 10 January 2008
 * Version: 1.2
 *
 * Source website: http://www.pgregg.com/projects/php/ip_in_range/
 * Version 1.2
 *
 * This software is Donationware - if you feel you have benefited from
 * the use of this tool then please consider a donation. The value of
 * which is entirely left up to your discretion.
 * http://www.pgregg.com/donate/
 *
 * Please do not remove this header, or source attibution from this file.
 */


// decbin32
// In order to simplify working with IP addresses (in binary) and their
// netmasks, it is easier to ensure that the binary strings are padded
// with zeros out to 32 characters - IP addresses are 32 bit numbers
Function decbin32 ($dec) {
  return str_pad(decbin($dec), 32, '0', STR_PAD_LEFT);
}

// ip_in_range
// This function takes 2 arguments, an IP address and a "range" in several
// different formats.
// Network ranges can be specified as:
// 1. Wildcard format:     1.2.3.*
// 2. CIDR format:         1.2.3/24  OR  1.2.3.4/255.255.255.0
// 3. Start-End IP format: 1.2.3.0-1.2.3.255
// The function will return true if the supplied IP is within the range.
// Note little validation is done on the range inputs - it expects you to
// use one of the above 3 formats.
Function ip_in_range($ip, $range) {
  if (strpos($range, '/') !== false) {
    // $range is in IP/NETMASK format
    list($range, $netmask) = explode('/', $range, 2);
    if (strpos($netmask, '.') !== false) {
      // $netmask is a 255.255.0.0 format
      $netmask = str_replace('*', '0', $netmask);
      $netmask_dec = ip2long($netmask);
      return ( (ip2long($ip) & $netmask_dec) == (ip2long($range) & $netmask_dec) );
    } else {
      // $netmask is a CIDR size block
      // fix the range argument
      $x = explode('.', $range);
      while(count($x)<4) $x[] = '0';
      list($a,$b,$c,$d) = $x;
      $range = sprintf("%u.%u.%u.%u", empty($a)?'0':$a, empty($b)?'0':$b,empty($c)?'0':$c,empty($d)?'0':$d);
      $range_dec = ip2long($range);
      $ip_dec = ip2long($ip);

      # Strategy 1 - Create the netmask with 'netmask' 1s and then fill it to 32 with 0s
      #$netmask_dec = bindec(str_pad('', $netmask, '1') . str_pad('', 32-$netmask, '0'));

      # Strategy 2 - Use math to create it
      $wildcard_dec = pow(2, (32-$netmask)) - 1;
      $netmask_dec = ~ $wildcard_dec;

      return (($ip_dec & $netmask_dec) == ($range_dec & $netmask_dec));
    }
  } else {
    // range might be 255.255.*.* or 1.2.3.0-1.2.3.255
    if (strpos($range, '*') !==false) { // a.b.*.* format
      // Just convert to A-B format by setting * to 0 for A and 255 for B
      $lower = str_replace('*', '0', $range);
      $upper = str_replace('*', '255', $range);
      $range = "$lower-$upper";
    }

    if (strpos($range, '-')!==false) { // A-B format
      list($lower, $upper) = explode('-', $range, 2);
      $lower_dec = (float)sprintf("%u",ip2long($lower));
      $upper_dec = (float)sprintf("%u",ip2long($upper));
      $ip_dec = (float)sprintf("%u",ip2long($ip));
      return ( ($ip_dec>=$lower_dec) && ($ip_dec<=$upper_dec) );
    }

    echo 'Range argument is not in 1.2.3.4/24 or 1.2.3.4/255.255.255.0 format';
    return false;
  }

}
?>

Unfortunately not. Hopefully the code here is stands on its own.

I've replaced it with a version from the Internet Archive.

How to check an IP address is within a range of two IPs in PHP? - Stac...

php ip range
Rectangle 27 6

PHP

You could use a function that returns the value:

function random() {
  return (float)rand()/(float)getrandmax();
}

// Generates
// 0.85552537614063
// 0.23554185613575
// 0.025269325846126
// 0.016418958098086
var random = function () {
  return Math.random();
};

// Generates
// 0.6855146484449506
// 0.910828611580655
// 0.46277225855737925
// 0.6367355801630765

@elclanrs solution is easier and doesn't need the cast in return.

There's a good question about the difference between PHP mt_rand() and rand() here:What's the disadvantage of mt_rand?

PHP equivalent of javascript Math.random() - Stack Overflow

php javascript random time
Rectangle 27 6

PHP

You could use a function that returns the value:

function random() {
  return (float)rand()/(float)getrandmax();
}

// Generates
// 0.85552537614063
// 0.23554185613575
// 0.025269325846126
// 0.016418958098086
var random = function () {
  return Math.random();
};

// Generates
// 0.6855146484449506
// 0.910828611580655
// 0.46277225855737925
// 0.6367355801630765

@elclanrs solution is easier and doesn't need the cast in return.

There's a good question about the difference between PHP mt_rand() and rand() here:What's the disadvantage of mt_rand?

PHP equivalent of javascript Math.random() - Stack Overflow

php javascript random time
Rectangle 27 61

PHP

Agreeing/expanding what has already been said, I don't think FastCGI will solve the problem.

Each request into Apache will use one worker thread until the request completes, which may be a long time for COMET requests.

This article on Ajaxian mentions using COMET on Apache, and that it is difficult. The problem isn't specific to PHP, and applies to any back-end CGI module you may want to use on Apache.

The suggested solution was to use the 'event' MPM module which changes the way requests are dispatched to worker threads.

This MPM tries to fix the 'keep alive problem' in HTTP. After a client completes the first request, the client can keep the connection open, and send further requests using the same socket. This can save signifigant overhead in creating TCP connections. However, Apache traditionally keeps an entire child process/thread waiting for data from the client, which brings its own disadvantages. To solve this problem, this MPM uses a dedicated thread to handle both the Listening sockets, and all sockets that are in a Keep Alive state.

Unfortunately, that doesn't work either, because it will only 'snooze' after a request is complete, waiting for a new request from the client.

Now, considering the other side of the problem, even if you resolve the issue with holding up one thread per comet request, you will still need one PHP thread per request - this is why FastCGI won't help.

You need something like Continuations which allow the comet requests to be resumed when the event they are triggered by is observed. AFAIK, this isn't something that's possible in PHP. I've only seen it in Java - see the Apache Tomcat server.

There's an article here about using a load balancer (HAProxy) to allow you to run both an apache server and a comet-enabled server (e.g. jetty, tomcat for Java) on port 80 of the same server.

+1 because Apache/PHP are not good options for scaling out a comet solution. Options for PHP users are 1) as you mentioned, crazy configurations of additional servers and proxies or 2) using a SaaS solution and offloading the comet stuff via something like WebSync On-Demand.

This is wrong in several aspects. If one wants to leave the one-thread-per-user method, it can be easily achieved by removing Apache as an intermediary and let PHP handle these requests. Of course, Apache works better at serving content, so I would run this apache-less PHP sever on a subdomain that does not serve any content.

@MikeHouston What about trying comet with php in IIS.?

@ravz, there's some stuff here about IIS and comet: stackoverflow.com/questions/1898848/comet-programming-in-iis, but I suspect the fast-cgi PHP module has the same limitations as with apache. It mentions a single threaded environment here: microsoft.com/web/platform/phponwindows.aspx - I don't use Windows servers myself, so I'm not sure about the threading model.

Using comet with PHP? - Stack Overflow

php comet
Rectangle 27 205

List of functions which accept callbacks

To build this list I used 2 sources. A Study In Scarlet and RATS. I have also added some of my own to the mix and people on this thread have helped out.

Edit: After posting this list I contacted the founder of RIPS and as of now this tools searches PHP code for the use of every function in this list.

exec           - Returns last line of commands output
passthru       - Passes commands output directly to the browser
system         - Passes commands output directly to the browser and returns last line
shell_exec     - Returns commands output
`` (backticks) - Same as shell_exec()
popen          - Opens read or write pipe to process of a command
proc_open      - Similar to popen() but greater degree of control
pcntl_exec     - Executes a program

Apart from eval there are other ways to execute PHP code: include/require can be used for remote code execution in the form of Local File Include and Remote File Include vulnerabilities.

eval()
assert()  - identical to eval()
preg_replace('/.*/e',...) - /e does an eval() on the match
create_function()
include()
include_once()
require()
require_once()
$_GET['func_name']($_GET['argument']);
$func = new ReflectionFunction($_GET['func_name']); $func->invoke(); or $func->invokeArgs(array());

These functions accept a string parameter which could be used to call a function of the attacker's choice. Depending on the function the attacker may or may not have the ability to pass a parameter. In that case an Information Disclosure function like phpinfo() could be used.

Function                     => Position of callback arguments
'ob_start'                   =>  0,
'array_diff_uassoc'          => -1,
'array_diff_ukey'            => -1,
'array_filter'               =>  1,
'array_intersect_uassoc'     => -1,
'array_intersect_ukey'       => -1,
'array_map'                  =>  0,
'array_reduce'               =>  1,
'array_udiff_assoc'          => -1,
'array_udiff_uassoc'         => array(-1, -2),
'array_udiff'                => -1,
'array_uintersect_assoc'     => -1,
'array_uintersect_uassoc'    => array(-1, -2),
'array_uintersect'           => -1,
'array_walk_recursive'       =>  1,
'array_walk'                 =>  1,
'assert_options'             =>  1,
'uasort'                     =>  1,
'uksort'                     =>  1,
'usort'                      =>  1,
'preg_replace_callback'      =>  1,
'spl_autoload_register'      =>  0,
'iterator_apply'             =>  1,
'call_user_func'             =>  0,
'call_user_func_array'       =>  0,
'register_shutdown_function' =>  0,
'register_tick_function'     =>  0,
'set_error_handler'          =>  0,
'set_exception_handler'      =>  0,
'session_set_save_handler'   => array(0, 1, 2, 3, 4, 5),
'sqlite_create_aggregate'    => array(2, 3),
'sqlite_create_function'     =>  2,

Most of these function calls are not sinks. But rather it maybe a vulnerability if any of the data returned is viewable to an attacker. If an attacker can see phpinfo() it is definitely a vulnerability.

phpinfo
posix_mkfifo
posix_getlogin
posix_ttyname
getenv
get_current_user
proc_get_status
get_cfg_var
disk_free_space
disk_total_space
diskfreespace
getcwd
getlastmo
getmygid
getmyinode
getmypid
getmyuid
extract - Opens the door for register_globals attacks (see study in scarlet).
parse_str -  works like extract if only one argument is given.  
putenv
ini_set
mail - has CRLF injection in the 3rd parameter, opens the door for spam. 
header - on old systems CRLF injection could be used for xss or other purposes, now it is still a problem if they do a header("location: ..."); and they do not die();. The script keeps executing after a call to header(), and will still print output normally. This is nasty if you are trying to protect an administrative area. 
proc_nice
proc_terminate
proc_close
pfsockopen
fsockopen
apache_child_terminate
posix_kill
posix_mkfifo
posix_setpgid
posix_setsid
posix_setuid

According to RATS all filesystem functions in php are nasty. Some of these don't seem very useful to the attacker. Others are more useful than you might think. For instance if allow_url_fopen=On then a url can be used as a file path, so a call to copy($_GET['s'], $_GET['d']); can be used to upload a PHP script anywhere on the system. Also if a site is vulnerable to a request send via GET everyone of those file system functions can be abused to channel and attack to another host through your server.

// open filesystem handler
fopen
tmpfile
bzopen
gzopen
SplFileObject->__construct
// write to filesystem (partially in combination with reading)
chgrp
chmod
chown
copy
file_put_contents
lchgrp
lchown
link
mkdir
move_uploaded_file
rename
rmdir
symlink
tempnam
touch
unlink
imagepng   - 2nd parameter is a path.
imagewbmp  - 2nd parameter is a path. 
image2wbmp - 2nd parameter is a path. 
imagejpeg  - 2nd parameter is a path.
imagexbm   - 2nd parameter is a path.
imagegif   - 2nd parameter is a path.
imagegd    - 2nd parameter is a path.
imagegd2   - 2nd parameter is a path.
iptcembed
ftp_get
ftp_nb_get
// read from filesystem
file_exists
file_get_contents
file
fileatime
filectime
filegroup
fileinode
filemtime
fileowner
fileperms
filesize
filetype
glob
is_dir
is_executable
is_file
is_link
is_readable
is_uploaded_file
is_writable
is_writeable
linkinfo
lstat
parse_ini_file
pathinfo
readfile
readlink
realpath
stat
gzfile
readgzfile
getimagesize
imagecreatefromgif
imagecreatefromjpeg
imagecreatefrompng
imagecreatefromwbmp
imagecreatefromxbm
imagecreatefromxpm
ftp_put
ftp_nb_put
exif_read_data
read_exif_data
exif_thumbnail
exif_imagetype
hash_file
hash_hmac_file
hash_update_file
md5_file
sha1_file
highlight_file
show_source
php_strip_whitespace
get_meta_tags

@whatnick Actually I don't see an appreciable difference between PHP and other web application languages. At the end of the day programmers need the ability to eval() code, to execute system commands, access a database, and read/write to files. This code can be influenced by an attacker, and that is a vulnerability.

So many functions banned! Are you the host of my website by any chance?

@Andrew Dunn haha, no. If you banned all of these functions than no PHP application would work. Especially include(), require(), and the file system functions.

@Rook : my thoughts exactly but these are for potential problems, not definite ones. If used correctly, none of these pose an immediate threat; but if they can be avoided they should be.

Imho preg_match with e is no harm. Manual says "Only preg_replace() uses this modifier; it is ignored by other PCRE functions."

security - Exploitable PHP functions - Stack Overflow

php security grep
Rectangle 27 205

List of functions which accept callbacks

To build this list I used 2 sources. A Study In Scarlet and RATS. I have also added some of my own to the mix and people on this thread have helped out.

Edit: After posting this list I contacted the founder of RIPS and as of now this tools searches PHP code for the use of every function in this list.

exec           - Returns last line of commands output
passthru       - Passes commands output directly to the browser
system         - Passes commands output directly to the browser and returns last line
shell_exec     - Returns commands output
`` (backticks) - Same as shell_exec()
popen          - Opens read or write pipe to process of a command
proc_open      - Similar to popen() but greater degree of control
pcntl_exec     - Executes a program

Apart from eval there are other ways to execute PHP code: include/require can be used for remote code execution in the form of Local File Include and Remote File Include vulnerabilities.

eval()
assert()  - identical to eval()
preg_replace('/.*/e',...) - /e does an eval() on the match
create_function()
include()
include_once()
require()
require_once()
$_GET['func_name']($_GET['argument']);
$func = new ReflectionFunction($_GET['func_name']); $func->invoke(); or $func->invokeArgs(array());

These functions accept a string parameter which could be used to call a function of the attacker's choice. Depending on the function the attacker may or may not have the ability to pass a parameter. In that case an Information Disclosure function like phpinfo() could be used.

Function                     => Position of callback arguments
'ob_start'                   =>  0,
'array_diff_uassoc'          => -1,
'array_diff_ukey'            => -1,
'array_filter'               =>  1,
'array_intersect_uassoc'     => -1,
'array_intersect_ukey'       => -1,
'array_map'                  =>  0,
'array_reduce'               =>  1,
'array_udiff_assoc'          => -1,
'array_udiff_uassoc'         => array(-1, -2),
'array_udiff'                => -1,
'array_uintersect_assoc'     => -1,
'array_uintersect_uassoc'    => array(-1, -2),
'array_uintersect'           => -1,
'array_walk_recursive'       =>  1,
'array_walk'                 =>  1,
'assert_options'             =>  1,
'uasort'                     =>  1,
'uksort'                     =>  1,
'usort'                      =>  1,
'preg_replace_callback'      =>  1,
'spl_autoload_register'      =>  0,
'iterator_apply'             =>  1,
'call_user_func'             =>  0,
'call_user_func_array'       =>  0,
'register_shutdown_function' =>  0,
'register_tick_function'     =>  0,
'set_error_handler'          =>  0,
'set_exception_handler'      =>  0,
'session_set_save_handler'   => array(0, 1, 2, 3, 4, 5),
'sqlite_create_aggregate'    => array(2, 3),
'sqlite_create_function'     =>  2,

Most of these function calls are not sinks. But rather it maybe a vulnerability if any of the data returned is viewable to an attacker. If an attacker can see phpinfo() it is definitely a vulnerability.

phpinfo
posix_mkfifo
posix_getlogin
posix_ttyname
getenv
get_current_user
proc_get_status
get_cfg_var
disk_free_space
disk_total_space
diskfreespace
getcwd
getlastmo
getmygid
getmyinode
getmypid
getmyuid
extract - Opens the door for register_globals attacks (see study in scarlet).
parse_str -  works like extract if only one argument is given.  
putenv
ini_set
mail - has CRLF injection in the 3rd parameter, opens the door for spam. 
header - on old systems CRLF injection could be used for xss or other purposes, now it is still a problem if they do a header("location: ..."); and they do not die();. The script keeps executing after a call to header(), and will still print output normally. This is nasty if you are trying to protect an administrative area. 
proc_nice
proc_terminate
proc_close
pfsockopen
fsockopen
apache_child_terminate
posix_kill
posix_mkfifo
posix_setpgid
posix_setsid
posix_setuid

According to RATS all filesystem functions in php are nasty. Some of these don't seem very useful to the attacker. Others are more useful than you might think. For instance if allow_url_fopen=On then a url can be used as a file path, so a call to copy($_GET['s'], $_GET['d']); can be used to upload a PHP script anywhere on the system. Also if a site is vulnerable to a request send via GET everyone of those file system functions can be abused to channel and attack to another host through your server.

// open filesystem handler
fopen
tmpfile
bzopen
gzopen
SplFileObject->__construct
// write to filesystem (partially in combination with reading)
chgrp
chmod
chown
copy
file_put_contents
lchgrp
lchown
link
mkdir
move_uploaded_file
rename
rmdir
symlink
tempnam
touch
unlink
imagepng   - 2nd parameter is a path.
imagewbmp  - 2nd parameter is a path. 
image2wbmp - 2nd parameter is a path. 
imagejpeg  - 2nd parameter is a path.
imagexbm   - 2nd parameter is a path.
imagegif   - 2nd parameter is a path.
imagegd    - 2nd parameter is a path.
imagegd2   - 2nd parameter is a path.
iptcembed
ftp_get
ftp_nb_get
// read from filesystem
file_exists
file_get_contents
file
fileatime
filectime
filegroup
fileinode
filemtime
fileowner
fileperms
filesize
filetype
glob
is_dir
is_executable
is_file
is_link
is_readable
is_uploaded_file
is_writable
is_writeable
linkinfo
lstat
parse_ini_file
pathinfo
readfile
readlink
realpath
stat
gzfile
readgzfile
getimagesize
imagecreatefromgif
imagecreatefromjpeg
imagecreatefrompng
imagecreatefromwbmp
imagecreatefromxbm
imagecreatefromxpm
ftp_put
ftp_nb_put
exif_read_data
read_exif_data
exif_thumbnail
exif_imagetype
hash_file
hash_hmac_file
hash_update_file
md5_file
sha1_file
highlight_file
show_source
php_strip_whitespace
get_meta_tags

@whatnick Actually I don't see an appreciable difference between PHP and other web application languages. At the end of the day programmers need the ability to eval() code, to execute system commands, access a database, and read/write to files. This code can be influenced by an attacker, and that is a vulnerability.

So many functions banned! Are you the host of my website by any chance?

@Andrew Dunn haha, no. If you banned all of these functions than no PHP application would work. Especially include(), require(), and the file system functions.

@Rook : my thoughts exactly but these are for potential problems, not definite ones. If used correctly, none of these pose an immediate threat; but if they can be avoided they should be.

Imho preg_match with e is no harm. Manual says "Only preg_replace() uses this modifier; it is ignored by other PCRE functions."

security - Exploitable PHP functions - Stack Overflow

php security grep
Rectangle 27 205

List of functions which accept callbacks

To build this list I used 2 sources. A Study In Scarlet and RATS. I have also added some of my own to the mix and people on this thread have helped out.

Edit: After posting this list I contacted the founder of RIPS and as of now this tools searches PHP code for the use of every function in this list.

exec           - Returns last line of commands output
passthru       - Passes commands output directly to the browser
system         - Passes commands output directly to the browser and returns last line
shell_exec     - Returns commands output
`` (backticks) - Same as shell_exec()
popen          - Opens read or write pipe to process of a command
proc_open      - Similar to popen() but greater degree of control
pcntl_exec     - Executes a program

Apart from eval there are other ways to execute PHP code: include/require can be used for remote code execution in the form of Local File Include and Remote File Include vulnerabilities.

eval()
assert()  - identical to eval()
preg_replace('/.*/e',...) - /e does an eval() on the match
create_function()
include()
include_once()
require()
require_once()
$_GET['func_name']($_GET['argument']);
$func = new ReflectionFunction($_GET['func_name']); $func->invoke(); or $func->invokeArgs(array());

These functions accept a string parameter which could be used to call a function of the attacker's choice. Depending on the function the attacker may or may not have the ability to pass a parameter. In that case an Information Disclosure function like phpinfo() could be used.

Function                     => Position of callback arguments
'ob_start'                   =>  0,
'array_diff_uassoc'          => -1,
'array_diff_ukey'            => -1,
'array_filter'               =>  1,
'array_intersect_uassoc'     => -1,
'array_intersect_ukey'       => -1,
'array_map'                  =>  0,
'array_reduce'               =>  1,
'array_udiff_assoc'          => -1,
'array_udiff_uassoc'         => array(-1, -2),
'array_udiff'                => -1,
'array_uintersect_assoc'     => -1,
'array_uintersect_uassoc'    => array(-1, -2),
'array_uintersect'           => -1,
'array_walk_recursive'       =>  1,
'array_walk'                 =>  1,
'assert_options'             =>  1,
'uasort'                     =>  1,
'uksort'                     =>  1,
'usort'                      =>  1,
'preg_replace_callback'      =>  1,
'spl_autoload_register'      =>  0,
'iterator_apply'             =>  1,
'call_user_func'             =>  0,
'call_user_func_array'       =>  0,
'register_shutdown_function' =>  0,
'register_tick_function'     =>  0,
'set_error_handler'          =>  0,
'set_exception_handler'      =>  0,
'session_set_save_handler'   => array(0, 1, 2, 3, 4, 5),
'sqlite_create_aggregate'    => array(2, 3),
'sqlite_create_function'     =>  2,

Most of these function calls are not sinks. But rather it maybe a vulnerability if any of the data returned is viewable to an attacker. If an attacker can see phpinfo() it is definitely a vulnerability.

phpinfo
posix_mkfifo
posix_getlogin
posix_ttyname
getenv
get_current_user
proc_get_status
get_cfg_var
disk_free_space
disk_total_space
diskfreespace
getcwd
getlastmo
getmygid
getmyinode
getmypid
getmyuid
extract - Opens the door for register_globals attacks (see study in scarlet).
parse_str -  works like extract if only one argument is given.  
putenv
ini_set
mail - has CRLF injection in the 3rd parameter, opens the door for spam. 
header - on old systems CRLF injection could be used for xss or other purposes, now it is still a problem if they do a header("location: ..."); and they do not die();. The script keeps executing after a call to header(), and will still print output normally. This is nasty if you are trying to protect an administrative area. 
proc_nice
proc_terminate
proc_close
pfsockopen
fsockopen
apache_child_terminate
posix_kill
posix_mkfifo
posix_setpgid
posix_setsid
posix_setuid

According to RATS all filesystem functions in php are nasty. Some of these don't seem very useful to the attacker. Others are more useful than you might think. For instance if allow_url_fopen=On then a url can be used as a file path, so a call to copy($_GET['s'], $_GET['d']); can be used to upload a PHP script anywhere on the system. Also if a site is vulnerable to a request send via GET everyone of those file system functions can be abused to channel and attack to another host through your server.

// open filesystem handler
fopen
tmpfile
bzopen
gzopen
SplFileObject->__construct
// write to filesystem (partially in combination with reading)
chgrp
chmod
chown
copy
file_put_contents
lchgrp
lchown
link
mkdir
move_uploaded_file
rename
rmdir
symlink
tempnam
touch
unlink
imagepng   - 2nd parameter is a path.
imagewbmp  - 2nd parameter is a path. 
image2wbmp - 2nd parameter is a path. 
imagejpeg  - 2nd parameter is a path.
imagexbm   - 2nd parameter is a path.
imagegif   - 2nd parameter is a path.
imagegd    - 2nd parameter is a path.
imagegd2   - 2nd parameter is a path.
iptcembed
ftp_get
ftp_nb_get
// read from filesystem
file_exists
file_get_contents
file
fileatime
filectime
filegroup
fileinode
filemtime
fileowner
fileperms
filesize
filetype
glob
is_dir
is_executable
is_file
is_link
is_readable
is_uploaded_file
is_writable
is_writeable
linkinfo
lstat
parse_ini_file
pathinfo
readfile
readlink
realpath
stat
gzfile
readgzfile
getimagesize
imagecreatefromgif
imagecreatefromjpeg
imagecreatefrompng
imagecreatefromwbmp
imagecreatefromxbm
imagecreatefromxpm
ftp_put
ftp_nb_put
exif_read_data
read_exif_data
exif_thumbnail
exif_imagetype
hash_file
hash_hmac_file
hash_update_file
md5_file
sha1_file
highlight_file
show_source
php_strip_whitespace
get_meta_tags

@whatnick Actually I don't see an appreciable difference between PHP and other web application languages. At the end of the day programmers need the ability to eval() code, to execute system commands, access a database, and read/write to files. This code can be influenced by an attacker, and that is a vulnerability.

So many functions banned! Are you the host of my website by any chance?

@Andrew Dunn haha, no. If you banned all of these functions than no PHP application would work. Especially include(), require(), and the file system functions.

@Rook : my thoughts exactly but these are for potential problems, not definite ones. If used correctly, none of these pose an immediate threat; but if they can be avoided they should be.

Imho preg_match with e is no harm. Manual says "Only preg_replace() uses this modifier; it is ignored by other PCRE functions."

security - Exploitable PHP functions - Stack Overflow

php security grep
Rectangle 27 205

List of functions which accept callbacks

To build this list I used 2 sources. A Study In Scarlet and RATS. I have also added some of my own to the mix and people on this thread have helped out.

Edit: After posting this list I contacted the founder of RIPS and as of now this tools searches PHP code for the use of every function in this list.

exec           - Returns last line of commands output
passthru       - Passes commands output directly to the browser
system         - Passes commands output directly to the browser and returns last line
shell_exec     - Returns commands output
`` (backticks) - Same as shell_exec()
popen          - Opens read or write pipe to process of a command
proc_open      - Similar to popen() but greater degree of control
pcntl_exec     - Executes a program

Apart from eval there are other ways to execute PHP code: include/require can be used for remote code execution in the form of Local File Include and Remote File Include vulnerabilities.

eval()
assert()  - identical to eval()
preg_replace('/.*/e',...) - /e does an eval() on the match
create_function()
include()
include_once()
require()
require_once()
$_GET['func_name']($_GET['argument']);
$func = new ReflectionFunction($_GET['func_name']); $func->invoke(); or $func->invokeArgs(array());

These functions accept a string parameter which could be used to call a function of the attacker's choice. Depending on the function the attacker may or may not have the ability to pass a parameter. In that case an Information Disclosure function like phpinfo() could be used.

Function                     => Position of callback arguments
'ob_start'                   =>  0,
'array_diff_uassoc'          => -1,
'array_diff_ukey'            => -1,
'array_filter'               =>  1,
'array_intersect_uassoc'     => -1,
'array_intersect_ukey'       => -1,
'array_map'                  =>  0,
'array_reduce'               =>  1,
'array_udiff_assoc'          => -1,
'array_udiff_uassoc'         => array(-1, -2),
'array_udiff'                => -1,
'array_uintersect_assoc'     => -1,
'array_uintersect_uassoc'    => array(-1, -2),
'array_uintersect'           => -1,
'array_walk_recursive'       =>  1,
'array_walk'                 =>  1,
'assert_options'             =>  1,
'uasort'                     =>  1,
'uksort'                     =>  1,
'usort'                      =>  1,
'preg_replace_callback'      =>  1,
'spl_autoload_register'      =>  0,
'iterator_apply'             =>  1,
'call_user_func'             =>  0,
'call_user_func_array'       =>  0,
'register_shutdown_function' =>  0,
'register_tick_function'     =>  0,
'set_error_handler'          =>  0,
'set_exception_handler'      =>  0,
'session_set_save_handler'   => array(0, 1, 2, 3, 4, 5),
'sqlite_create_aggregate'    => array(2, 3),
'sqlite_create_function'     =>  2,

Most of these function calls are not sinks. But rather it maybe a vulnerability if any of the data returned is viewable to an attacker. If an attacker can see phpinfo() it is definitely a vulnerability.

phpinfo
posix_mkfifo
posix_getlogin
posix_ttyname
getenv
get_current_user
proc_get_status
get_cfg_var
disk_free_space
disk_total_space
diskfreespace
getcwd
getlastmo
getmygid
getmyinode
getmypid
getmyuid
extract - Opens the door for register_globals attacks (see study in scarlet).
parse_str -  works like extract if only one argument is given.  
putenv
ini_set
mail - has CRLF injection in the 3rd parameter, opens the door for spam. 
header - on old systems CRLF injection could be used for xss or other purposes, now it is still a problem if they do a header("location: ..."); and they do not die();. The script keeps executing after a call to header(), and will still print output normally. This is nasty if you are trying to protect an administrative area. 
proc_nice
proc_terminate
proc_close
pfsockopen
fsockopen
apache_child_terminate
posix_kill
posix_mkfifo
posix_setpgid
posix_setsid
posix_setuid

According to RATS all filesystem functions in php are nasty. Some of these don't seem very useful to the attacker. Others are more useful than you might think. For instance if allow_url_fopen=On then a url can be used as a file path, so a call to copy($_GET['s'], $_GET['d']); can be used to upload a PHP script anywhere on the system. Also if a site is vulnerable to a request send via GET everyone of those file system functions can be abused to channel and attack to another host through your server.

// open filesystem handler
fopen
tmpfile
bzopen
gzopen
SplFileObject->__construct
// write to filesystem (partially in combination with reading)
chgrp
chmod
chown
copy
file_put_contents
lchgrp
lchown
link
mkdir
move_uploaded_file
rename
rmdir
symlink
tempnam
touch
unlink
imagepng   - 2nd parameter is a path.
imagewbmp  - 2nd parameter is a path. 
image2wbmp - 2nd parameter is a path. 
imagejpeg  - 2nd parameter is a path.
imagexbm   - 2nd parameter is a path.
imagegif   - 2nd parameter is a path.
imagegd    - 2nd parameter is a path.
imagegd2   - 2nd parameter is a path.
iptcembed
ftp_get
ftp_nb_get
// read from filesystem
file_exists
file_get_contents
file
fileatime
filectime
filegroup
fileinode
filemtime
fileowner
fileperms
filesize
filetype
glob
is_dir
is_executable
is_file
is_link
is_readable
is_uploaded_file
is_writable
is_writeable
linkinfo
lstat
parse_ini_file
pathinfo
readfile
readlink
realpath
stat
gzfile
readgzfile
getimagesize
imagecreatefromgif
imagecreatefromjpeg
imagecreatefrompng
imagecreatefromwbmp
imagecreatefromxbm
imagecreatefromxpm
ftp_put
ftp_nb_put
exif_read_data
read_exif_data
exif_thumbnail
exif_imagetype
hash_file
hash_hmac_file
hash_update_file
md5_file
sha1_file
highlight_file
show_source
php_strip_whitespace
get_meta_tags

@whatnick Actually I don't see an appreciable difference between PHP and other web application languages. At the end of the day programmers need the ability to eval() code, to execute system commands, access a database, and read/write to files. This code can be influenced by an attacker, and that is a vulnerability.

So many functions banned! Are you the host of my website by any chance?

@Andrew Dunn haha, no. If you banned all of these functions than no PHP application would work. Especially include(), require(), and the file system functions.

@Rook : my thoughts exactly but these are for potential problems, not definite ones. If used correctly, none of these pose an immediate threat; but if they can be avoided they should be.

Imho preg_match with e is no harm. Manual says "Only preg_replace() uses this modifier; it is ignored by other PCRE functions."

security - Exploitable PHP functions - Stack Overflow

php security grep
Rectangle 27 61

PHP

Agreeing/expanding what has already been said, I don't think FastCGI will solve the problem.

Each request into Apache will use one worker thread until the request completes, which may be a long time for COMET requests.

This article on Ajaxian mentions using COMET on Apache, and that it is difficult. The problem isn't specific to PHP, and applies to any back-end CGI module you may want to use on Apache.

The suggested solution was to use the 'event' MPM module which changes the way requests are dispatched to worker threads.

This MPM tries to fix the 'keep alive problem' in HTTP. After a client completes the first request, the client can keep the connection open, and send further requests using the same socket. This can save signifigant overhead in creating TCP connections. However, Apache traditionally keeps an entire child process/thread waiting for data from the client, which brings its own disadvantages. To solve this problem, this MPM uses a dedicated thread to handle both the Listening sockets, and all sockets that are in a Keep Alive state.

Unfortunately, that doesn't work either, because it will only 'snooze' after a request is complete, waiting for a new request from the client.

Now, considering the other side of the problem, even if you resolve the issue with holding up one thread per comet request, you will still need one PHP thread per request - this is why FastCGI won't help.

You need something like Continuations which allow the comet requests to be resumed when the event they are triggered by is observed. AFAIK, this isn't something that's possible in PHP. I've only seen it in Java - see the Apache Tomcat server.

There's an article here about using a load balancer (HAProxy) to allow you to run both an apache server and a comet-enabled server (e.g. jetty, tomcat for Java) on port 80 of the same server.

+1 because Apache/PHP are not good options for scaling out a comet solution. Options for PHP users are 1) as you mentioned, crazy configurations of additional servers and proxies or 2) using a SaaS solution and offloading the comet stuff via something like WebSync On-Demand.

This is wrong in several aspects. If one wants to leave the one-thread-per-user method, it can be easily achieved by removing Apache as an intermediary and let PHP handle these requests. Of course, Apache works better at serving content, so I would run this apache-less PHP sever on a subdomain that does not serve any content.

@MikeHouston What about trying comet with php in IIS.?

@ravz, there's some stuff here about IIS and comet: stackoverflow.com/questions/1898848/comet-programming-in-iis, but I suspect the fast-cgi PHP module has the same limitations as with apache. It mentions a single threaded environment here: microsoft.com/web/platform/phponwindows.aspx - I don't use Windows servers myself, so I'm not sure about the threading model.

Using comet with PHP? - Stack Overflow

php comet
Rectangle 27 61

PHP

Agreeing/expanding what has already been said, I don't think FastCGI will solve the problem.

Each request into Apache will use one worker thread until the request completes, which may be a long time for COMET requests.

This article on Ajaxian mentions using COMET on Apache, and that it is difficult. The problem isn't specific to PHP, and applies to any back-end CGI module you may want to use on Apache.

The suggested solution was to use the 'event' MPM module which changes the way requests are dispatched to worker threads.

This MPM tries to fix the 'keep alive problem' in HTTP. After a client completes the first request, the client can keep the connection open, and send further requests using the same socket. This can save signifigant overhead in creating TCP connections. However, Apache traditionally keeps an entire child process/thread waiting for data from the client, which brings its own disadvantages. To solve this problem, this MPM uses a dedicated thread to handle both the Listening sockets, and all sockets that are in a Keep Alive state.

Unfortunately, that doesn't work either, because it will only 'snooze' after a request is complete, waiting for a new request from the client.

Now, considering the other side of the problem, even if you resolve the issue with holding up one thread per comet request, you will still need one PHP thread per request - this is why FastCGI won't help.

You need something like Continuations which allow the comet requests to be resumed when the event they are triggered by is observed. AFAIK, this isn't something that's possible in PHP. I've only seen it in Java - see the Apache Tomcat server.

There's an article here about using a load balancer (HAProxy) to allow you to run both an apache server and a comet-enabled server (e.g. jetty, tomcat for Java) on port 80 of the same server.

+1 because Apache/PHP are not good options for scaling out a comet solution. Options for PHP users are 1) as you mentioned, crazy configurations of additional servers and proxies or 2) using a SaaS solution and offloading the comet stuff via something like WebSync On-Demand.

This is wrong in several aspects. If one wants to leave the one-thread-per-user method, it can be easily achieved by removing Apache as an intermediary and let PHP handle these requests. Of course, Apache works better at serving content, so I would run this apache-less PHP sever on a subdomain that does not serve any content.

@MikeHouston What about trying comet with php in IIS.?

@ravz, there's some stuff here about IIS and comet: stackoverflow.com/questions/1898848/comet-programming-in-iis, but I suspect the fast-cgi PHP module has the same limitations as with apache. It mentions a single threaded environment here: microsoft.com/web/platform/phponwindows.aspx - I don't use Windows servers myself, so I'm not sure about the threading model.

Using comet with PHP? - Stack Overflow

php comet
Rectangle 27 187

Equivalent pdo_* functions in place of mysql_*

The analytic and synthetic reasons were already mentioned. For newcomers there's a more significant incentive to stop using the dated mysql_ functions.

It's mostly the bound parameters which can simplify code. And with excellent tutorials (as seen above) the transition to PDO isn't overly arduous.

Using <pdo_mysql.php> you can switch from the old mysql_ functions with minimal effort. It adds pdo_ function wrappers which replace their mysql_ counterparts.

Simply include_once("pdo_mysql.php"); in each invocation script that has to interact with the database.

Remove the mysql_ function prefix everywhere and replace it with pdo_.

connect()
query()
num_rows()
insert_id()
fetch_array()
fetch_assoc()
pdo_
real_escape_string()
  • Your code will work alike and still mostly look the same: include_once("pdo_mysql.php"); pdo_connect("localhost", "usrABC", "pw1234567"); pdo_select_db("test"); $result = pdo_query("SELECT title, html FROM pages"); while ($row = pdo_fetch_assoc($result)) { print "$row[title] - $row[html]"; }

Et voil. Your code is using PDO. Now it's time to actually utilize it.

You just need a less unwieldy API.

pdo_query() adds very facile support for bound parameters. Converting old code is straightforward:

Move your variables out of the SQL string.

  • Add them as comma delimited function parameters to pdo_query().
  • Place question marks ? as placeholders where the variables were before.
  • Get rid of ' single quotes that previously enclosed string values/variables.

Often string variables aren't just interpolated into SQL, but concatenated with escaping calls in between.

pdo_query("SELECT id, links, html, title, user, date FROM articles
   WHERE title='" . pdo_real_escape_string($title) . "' OR id='".
   pdo_real_escape_string($title) . "' AND user <> '" .
   pdo_real_escape_string($root) . "' ORDER BY date")

With ? placeholders applied you don't have to bother with that:

pdo_query("SELECT id, links, html, title, user, date FROM articles
   WHERE title=? OR id=? AND user<>? ORDER BY date", $title, $id, $root)

Remember that pdo_* still allows either or. Just don't escape a variable and bind it in the same query.

  • The placeholder feature is provided by the real PDO behind it.
:named

More importantly you can pass $_REQUEST[] variables safely behind any query. When submitted <form> fields match the database structure exactly it's even shorter:

So much simplicity. But let's get back to some more rewriting advises and technical reasons on why you may want to get rid of mysql_ and escaping.

Once you have converted all mysql_ calls to pdo_query with bound params, remove all redundant pdo_real_escape_string calls.

In particular you should fix any sanitize or clean or filterThis or clean_data functions as advertised by dated tutorials in one form or the other:

function sanitize($str) {
   return trim(strip_tags(htmlentities(pdo_real_escape_string($str))));
}

Most glaring bug here is the lack of documentation. More significantly the order of filtering was in exactly the wrong order.

Correct order would have been: deprecatedly stripslashes as the innermost call, then trim, afterwards strip_tags, htmlentities for output context, and only lastly the _escape_string as its application should directly preceed the SQL intersparsing.

_real_escape_string

You may have to keep the rest of your sanitize() function for now if your database and application flow expect HTML-context-safe strings. Add a comment that it applies only HTML escaping henceforth.

If there was any mention of stripslashes() in your sanitize function, it may indicate a higher level oversight.

Historic note on magic_quotes. That feature is rightly deprecated. It's often incorrectly portrayed as failed security feature however. But magic_quotes are as much a failed security feature as tennis balls have failed as nutrition source. That simply wasn't their purpose.

The original implementation in PHP2/FI introduced it explicitly with just "quotes will be automatically escaped making it easier to pass form data directly to msql queries". Notably it was accidentially safe to use with mSQL, as that supported ASCII only. Then PHP3/Zend reintroduced magic_quotes for MySQL and misdocumented it. But originally it was just a convenience feature, not intend for security.

With bound parameters you separate SQL code and SQL-context values in your PHP code. But it doesn't get shuffled up again behind the scenes (except with PDO::EMULATE_PREPARES). Your database receives the unvaried SQL commands and 1:1 variable values.

While this answer stresses that you should care about the readability advantages of dropping mysql_. There's occasionally also a performance advantage (repeated INSERTs with just differing values) due to this visible and technical data/code separation.

Beware that parameter binding still isn't a magic one-stop solution against all SQL injections. It handles the most common use for data/values. But can't whitelist column name / table identifiers, help with dynamic clause construction, or just plain array value lists.

These pdo_* wrapper functions make a coding-friendly stop-gap API. (It's pretty much what MYSQLI could have been if it wasn't for the idiosyncratic function signature shift). They also expose the real PDO at most times. Rewriting doesn't have to stop at using the new pdo_ function names. You could one by one transition each pdo_query() into a plain $pdo->prepare()->execute() call.

$result = pdo_query("SELECT * FROM tbl");
while ($row = pdo_fetch_assoc($result)) {

Can be replaced with just an foreach iteration:

foreach ($result as $row) {

Or better yet a direct and complete array retrieval:

$result->fetchAll();
mysql_
pdo_query()

Unless you also introduce parameter binding or can utilize something else from the nicer API, it's a pointless switch. I hope it's portrayed simple enough to not further the discouragement to newcomers. (Education usually works better than prohibition.)

While it qualifies for the simplest-thing-that-could-possibly-work category, it's also still very experimental code. I just wrote it over the weekend. There's a plethora of alternatives however. Just google for PHP database abstraction and browse a little. There always have been and will be lots of excellent libraries for such tasks.

If you want to simplify your database interaction further, mappers like Paris/Idiorm are worth a try. Just like nobody uses the bland DOM in JavaScript anymore, you don't have to babysit a raw database interface nowadays.

Thanks. I'm mainly fond of the abstract pictograms visualizing parameterized queries. But I'll probably expand more on a later second conversion from pdo_query() to real PDO:: usage.

pdo_query("INSERT INTO pages VALUES (?,?,?,?,?)", $_POST);
pdo_query("INSERT INTO users VALUES (?, ?, ?), $_POST);  $_POST = array( 'username' => 'lawl', 'password' => '123', 'is_admin' => 'true');

@mario i'm thinking about using your pdo_* functions in a major legacy codebase. At the moment, i'm just experimenting, but already found a bug. Is there any way i can contribute to this project? Is 0.9.2 the latest version? THX!

@Tom Sure, albeit it's not maintained much (0.9.2 was the last), you can create a fossil account, add to the wiki or file a bug report (without registration IIRC).

mysql - Why shouldn't I use mysql_* functions in PHP? - Stack Overflow

php mysql database
Rectangle 27 181

Equivalent pdo_* functions in place of mysql_*

The analytic and synthetic reasons were already mentioned. For newcomers there's a more significant incentive to stop using the dated mysql_ functions.

It's mostly the bound parameters which can simplify code. And with excellent tutorials (as seen above) the transition to PDO isn't overly arduous.

Using <pdo_mysql.php> you can switch from the old mysql_ functions with minimal effort. It adds pdo_ function wrappers which replace their mysql_ counterparts.

Simply include_once("pdo_mysql.php"); in each invocation script that has to interact with the database.

Remove the mysql_ function prefix everywhere and replace it with pdo_.

connect()
query()
num_rows()
insert_id()
fetch_array()
fetch_assoc()
pdo_
real_escape_string()
  • Your code will work alike and still mostly look the same: include_once("pdo_mysql.php"); pdo_connect("localhost", "usrABC", "pw1234567"); pdo_select_db("test"); $result = pdo_query("SELECT title, html FROM pages"); while ($row = pdo_fetch_assoc($result)) { print "$row[title] - $row[html]"; }

Et voil. Your code is using PDO. Now it's time to actually utilize it.

You just need a less unwieldy API.

pdo_query() adds very facile support for bound parameters. Converting old code is straightforward:

Move your variables out of the SQL string.

  • Add them as comma delimited function parameters to pdo_query().
  • Place question marks ? as placeholders where the variables were before.
  • Get rid of ' single quotes that previously enclosed string values/variables.

Often string variables aren't just interpolated into SQL, but concatenated with escaping calls in between.

pdo_query("SELECT id, links, html, title, user, date FROM articles
   WHERE title='" . pdo_real_escape_string($title) . "' OR id='".
   pdo_real_escape_string($title) . "' AND user <> '" .
   pdo_real_escape_string($root) . "' ORDER BY date")

With ? placeholders applied you don't have to bother with that:

pdo_query("SELECT id, links, html, title, user, date FROM articles
   WHERE title=? OR id=? AND user<>? ORDER BY date", $title, $id, $root)

Remember that pdo_* still allows either or. Just don't escape a variable and bind it in the same query.

  • The placeholder feature is provided by the real PDO behind it.
:named

More importantly you can pass $_REQUEST[] variables safely behind any query. When submitted <form> fields match the database structure exactly it's even shorter:

So much simplicity. But let's get back to some more rewriting advises and technical reasons on why you may want to get rid of mysql_ and escaping.

Once you have converted all mysql_ calls to pdo_query with bound params, remove all redundant pdo_real_escape_string calls.

In particular you should fix any sanitize or clean or filterThis or clean_data functions as advertised by dated tutorials in one form or the other:

function sanitize($str) {
   return trim(strip_tags(htmlentities(pdo_real_escape_string($str))));
}

Most glaring bug here is the lack of documentation. More significantly the order of filtering was in exactly the wrong order.

Correct order would have been: deprecatedly stripslashes as the innermost call, then trim, afterwards strip_tags, htmlentities for output context, and only lastly the _escape_string as its application should directly preceed the SQL intersparsing.

_real_escape_string

You may have to keep the rest of your sanitize() function for now if your database and application flow expect HTML-context-safe strings. Add a comment that it applies only HTML escaping henceforth.

If there was any mention of stripslashes() in your sanitize function, it may indicate a higher level oversight.

Historic note on magic_quotes. That feature is rightly deprecated. It's often incorrectly portrayed as failed security feature however. But magic_quotes are as much a failed security feature as tennis balls have failed as nutrition source. That simply wasn't their purpose.

The original implementation in PHP2/FI introduced it explicitly with just "quotes will be automatically escaped making it easier to pass form data directly to msql queries". Notably it was accidentially safe to use with mSQL, as that supported ASCII only. Then PHP3/Zend reintroduced magic_quotes for MySQL and misdocumented it. But originally it was just a convenience feature, not intend for security.

With bound parameters you separate SQL code and SQL-context values in your PHP code. But it doesn't get shuffled up again behind the scenes (except with PDO::EMULATE_PREPARES). Your database receives the unvaried SQL commands and 1:1 variable values.

While this answer stresses that you should care about the readability advantages of dropping mysql_. There's occasionally also a performance advantage (repeated INSERTs with just differing values) due to this visible and technical data/code separation.

Beware that parameter binding still isn't a magic one-stop solution against all SQL injections. It handles the most common use for data/values. But can't whitelist column name / table identifiers, help with dynamic clause construction, or just plain array value lists.

These pdo_* wrapper functions make a coding-friendly stop-gap API. (It's pretty much what MYSQLI could have been if it wasn't for the idiosyncratic function signature shift). They also expose the real PDO at most times. Rewriting doesn't have to stop at using the new pdo_ function names. You could one by one transition each pdo_query() into a plain $pdo->prepare()->execute() call.

$result = pdo_query("SELECT * FROM tbl");
while ($row = pdo_fetch_assoc($result)) {

Can be replaced with just an foreach iteration:

foreach ($result as $row) {

Or better yet a direct and complete array retrieval:

$result->fetchAll();
mysql_
pdo_query()

Unless you also introduce parameter binding or can utilize something else from the nicer API, it's a pointless switch. I hope it's portrayed simple enough to not further the discouragement to newcomers. (Education usually works better than prohibition.)

While it qualifies for the simplest-thing-that-could-possibly-work category, it's also still very experimental code. I just wrote it over the weekend. There's a plethora of alternatives however. Just google for PHP database abstraction and browse a little. There always have been and will be lots of excellent libraries for such tasks.

If you want to simplify your database interaction further, mappers like Paris/Idiorm are worth a try. Just like nobody uses the bland DOM in JavaScript anymore, you don't have to babysit a raw database interface nowadays.

Thanks. I'm mainly fond of the abstract pictograms visualizing parameterized queries. But I'll probably expand more on a later second conversion from pdo_query() to real PDO:: usage.

pdo_query("INSERT INTO pages VALUES (?,?,?,?,?)", $_POST);
pdo_query("INSERT INTO users VALUES (?, ?, ?), $_POST);  $_POST = array( 'username' => 'lawl', 'password' => '123', 'is_admin' => 'true');

@mario i'm thinking about using your pdo_* functions in a major legacy codebase. At the moment, i'm just experimenting, but already found a bug. Is there any way i can contribute to this project? Is 0.9.2 the latest version? THX!

@Tom Sure, albeit it's not maintained much (0.9.2 was the last), you can create a fossil account, add to the wiki or file a bug report (without registration IIRC).

mysql - Why shouldn't I use mysql_* functions in PHP? - Stack Overflow

php mysql database
Rectangle 27 181

Equivalent pdo_* functions in place of mysql_*

The analytic and synthetic reasons were already mentioned. For newcomers there's a more significant incentive to stop using the dated mysql_ functions.

It's mostly the bound parameters which can simplify code. And with excellent tutorials (as seen above) the transition to PDO isn't overly arduous.

Using <pdo_mysql.php> you can switch from the old mysql_ functions with minimal effort. It adds pdo_ function wrappers which replace their mysql_ counterparts.

Simply include_once("pdo_mysql.php"); in each invocation script that has to interact with the database.

Remove the mysql_ function prefix everywhere and replace it with pdo_.

connect()
query()
num_rows()
insert_id()
fetch_array()
fetch_assoc()
pdo_
real_escape_string()
  • Your code will work alike and still mostly look the same: include_once("pdo_mysql.php"); pdo_connect("localhost", "usrABC", "pw1234567"); pdo_select_db("test"); $result = pdo_query("SELECT title, html FROM pages"); while ($row = pdo_fetch_assoc($result)) { print "$row[title] - $row[html]"; }

Et voil. Your code is using PDO. Now it's time to actually utilize it.

You just need a less unwieldy API.

pdo_query() adds very facile support for bound parameters. Converting old code is straightforward:

Move your variables out of the SQL string.

  • Add them as comma delimited function parameters to pdo_query().
  • Place question marks ? as placeholders where the variables were before.
  • Get rid of ' single quotes that previously enclosed string values/variables.

Often string variables aren't just interpolated into SQL, but concatenated with escaping calls in between.

pdo_query("SELECT id, links, html, title, user, date FROM articles
   WHERE title='" . pdo_real_escape_string($title) . "' OR id='".
   pdo_real_escape_string($title) . "' AND user <> '" .
   pdo_real_escape_string($root) . "' ORDER BY date")

With ? placeholders applied you don't have to bother with that:

pdo_query("SELECT id, links, html, title, user, date FROM articles
   WHERE title=? OR id=? AND user<>? ORDER BY date", $title, $id, $root)

Remember that pdo_* still allows either or. Just don't escape a variable and bind it in the same query.

  • The placeholder feature is provided by the real PDO behind it.
:named

More importantly you can pass $_REQUEST[] variables safely behind any query. When submitted <form> fields match the database structure exactly it's even shorter:

So much simplicity. But let's get back to some more rewriting advises and technical reasons on why you may want to get rid of mysql_ and escaping.

Once you have converted all mysql_ calls to pdo_query with bound params, remove all redundant pdo_real_escape_string calls.

In particular you should fix any sanitize or clean or filterThis or clean_data functions as advertised by dated tutorials in one form or the other:

function sanitize($str) {
   return trim(strip_tags(htmlentities(pdo_real_escape_string($str))));
}

Most glaring bug here is the lack of documentation. More significantly the order of filtering was in exactly the wrong order.

Correct order would have been: deprecatedly stripslashes as the innermost call, then trim, afterwards strip_tags, htmlentities for output context, and only lastly the _escape_string as its application should directly preceed the SQL intersparsing.

_real_escape_string

You may have to keep the rest of your sanitize() function for now if your database and application flow expect HTML-context-safe strings. Add a comment that it applies only HTML escaping henceforth.

If there was any mention of stripslashes() in your sanitize function, it may indicate a higher level oversight.

Historic note on magic_quotes. That feature is rightly deprecated. It's often incorrectly portrayed as failed security feature however. But magic_quotes are as much a failed security feature as tennis balls have failed as nutrition source. That simply wasn't their purpose.

The original implementation in PHP2/FI introduced it explicitly with just "quotes will be automatically escaped making it easier to pass form data directly to msql queries". Notably it was accidentially safe to use with mSQL, as that supported ASCII only. Then PHP3/Zend reintroduced magic_quotes for MySQL and misdocumented it. But originally it was just a convenience feature, not intend for security.

With bound parameters you separate SQL code and SQL-context values in your PHP code. But it doesn't get shuffled up again behind the scenes (except with PDO::EMULATE_PREPARES). Your database receives the unvaried SQL commands and 1:1 variable values.

While this answer stresses that you should care about the readability advantages of dropping mysql_. There's occasionally also a performance advantage (repeated INSERTs with just differing values) due to this visible and technical data/code separation.

Beware that parameter binding still isn't a magic one-stop solution against all SQL injections. It handles the most common use for data/values. But can't whitelist column name / table identifiers, help with dynamic clause construction, or just plain array value lists.

These pdo_* wrapper functions make a coding-friendly stop-gap API. (It's pretty much what MYSQLI could have been if it wasn't for the idiosyncratic function signature shift). They also expose the real PDO at most times. Rewriting doesn't have to stop at using the new pdo_ function names. You could one by one transition each pdo_query() into a plain $pdo->prepare()->execute() call.

$result = pdo_query("SELECT * FROM tbl");
while ($row = pdo_fetch_assoc($result)) {

Can be replaced with just an foreach iteration:

foreach ($result as $row) {

Or better yet a direct and complete array retrieval:

$result->fetchAll();
mysql_
pdo_query()

Unless you also introduce parameter binding or can utilize something else from the nicer API, it's a pointless switch. I hope it's portrayed simple enough to not further the discouragement to newcomers. (Education usually works better than prohibition.)

While it qualifies for the simplest-thing-that-could-possibly-work category, it's also still very experimental code. I just wrote it over the weekend. There's a plethora of alternatives however. Just google for PHP database abstraction and browse a little. There always have been and will be lots of excellent libraries for such tasks.

If you want to simplify your database interaction further, mappers like Paris/Idiorm are worth a try. Just like nobody uses the bland DOM in JavaScript anymore, you don't have to babysit a raw database interface nowadays.

Thanks. I'm mainly fond of the abstract pictograms visualizing parameterized queries. But I'll probably expand more on a later second conversion from pdo_query() to real PDO:: usage.

pdo_query("INSERT INTO pages VALUES (?,?,?,?,?)", $_POST);
pdo_query("INSERT INTO users VALUES (?, ?, ?), $_POST);  $_POST = array( 'username' => 'lawl', 'password' => '123', 'is_admin' => 'true');

@mario i'm thinking about using your pdo_* functions in a major legacy codebase. At the moment, i'm just experimenting, but already found a bug. Is there any way i can contribute to this project? Is 0.9.2 the latest version? THX!

@Tom Sure, albeit it's not maintained much (0.9.2 was the last), you can create a fossil account, add to the wiki or file a bug report (without registration IIRC).

mysql - Why shouldn't I use mysql_* functions in PHP? - Stack Overflow

php mysql database
Rectangle 27 181

Equivalent pdo_* functions in place of mysql_*

The analytic and synthetic reasons were already mentioned. For newcomers there's a more significant incentive to stop using the dated mysql_ functions.

It's mostly the bound parameters which can simplify code. And with excellent tutorials (as seen above) the transition to PDO isn't overly arduous.

Using <pdo_mysql.php> you can switch from the old mysql_ functions with minimal effort. It adds pdo_ function wrappers which replace their mysql_ counterparts.

Simply include_once("pdo_mysql.php"); in each invocation script that has to interact with the database.

Remove the mysql_ function prefix everywhere and replace it with pdo_.

connect()
query()
num_rows()
insert_id()
fetch_array()
fetch_assoc()
pdo_
real_escape_string()
  • Your code will work alike and still mostly look the same: include_once("pdo_mysql.php"); pdo_connect("localhost", "usrABC", "pw1234567"); pdo_select_db("test"); $result = pdo_query("SELECT title, html FROM pages"); while ($row = pdo_fetch_assoc($result)) { print "$row[title] - $row[html]"; }

Et voil. Your code is using PDO. Now it's time to actually utilize it.

You just need a less unwieldy API.

pdo_query() adds very facile support for bound parameters. Converting old code is straightforward:

Move your variables out of the SQL string.

  • Add them as comma delimited function parameters to pdo_query().
  • Place question marks ? as placeholders where the variables were before.
  • Get rid of ' single quotes that previously enclosed string values/variables.

Often string variables aren't just interpolated into SQL, but concatenated with escaping calls in between.

pdo_query("SELECT id, links, html, title, user, date FROM articles
   WHERE title='" . pdo_real_escape_string($title) . "' OR id='".
   pdo_real_escape_string($title) . "' AND user <> '" .
   pdo_real_escape_string($root) . "' ORDER BY date")

With ? placeholders applied you don't have to bother with that:

pdo_query("SELECT id, links, html, title, user, date FROM articles
   WHERE title=? OR id=? AND user<>? ORDER BY date", $title, $id, $root)

Remember that pdo_* still allows either or. Just don't escape a variable and bind it in the same query.

  • The placeholder feature is provided by the real PDO behind it.
:named

More importantly you can pass $_REQUEST[] variables safely behind any query. When submitted <form> fields match the database structure exactly it's even shorter:

So much simplicity. But let's get back to some more rewriting advises and technical reasons on why you may want to get rid of mysql_ and escaping.

Once you have converted all mysql_ calls to pdo_query with bound params, remove all redundant pdo_real_escape_string calls.

In particular you should fix any sanitize or clean or filterThis or clean_data functions as advertised by dated tutorials in one form or the other:

function sanitize($str) {
   return trim(strip_tags(htmlentities(pdo_real_escape_string($str))));
}

Most glaring bug here is the lack of documentation. More significantly the order of filtering was in exactly the wrong order.

Correct order would have been: deprecatedly stripslashes as the innermost call, then trim, afterwards strip_tags, htmlentities for output context, and only lastly the _escape_string as its application should directly preceed the SQL intersparsing.

_real_escape_string

You may have to keep the rest of your sanitize() function for now if your database and application flow expect HTML-context-safe strings. Add a comment that it applies only HTML escaping henceforth.

If there was any mention of stripslashes() in your sanitize function, it may indicate a higher level oversight.

Historic note on magic_quotes. That feature is rightly deprecated. It's often incorrectly portrayed as failed security feature however. But magic_quotes are as much a failed security feature as tennis balls have failed as nutrition source. That simply wasn't their purpose.

The original implementation in PHP2/FI introduced it explicitly with just "quotes will be automatically escaped making it easier to pass form data directly to msql queries". Notably it was accidentially safe to use with mSQL, as that supported ASCII only. Then PHP3/Zend reintroduced magic_quotes for MySQL and misdocumented it. But originally it was just a convenience feature, not intend for security.

With bound parameters you separate SQL code and SQL-context values in your PHP code. But it doesn't get shuffled up again behind the scenes (except with PDO::EMULATE_PREPARES). Your database receives the unvaried SQL commands and 1:1 variable values.

While this answer stresses that you should care about the readability advantages of dropping mysql_. There's occasionally also a performance advantage (repeated INSERTs with just differing values) due to this visible and technical data/code separation.

Beware that parameter binding still isn't a magic one-stop solution against all SQL injections. It handles the most common use for data/values. But can't whitelist column name / table identifiers, help with dynamic clause construction, or just plain array value lists.

These pdo_* wrapper functions make a coding-friendly stop-gap API. (It's pretty much what MYSQLI could have been if it wasn't for the idiosyncratic function signature shift). They also expose the real PDO at most times. Rewriting doesn't have to stop at using the new pdo_ function names. You could one by one transition each pdo_query() into a plain $pdo->prepare()->execute() call.

$result = pdo_query("SELECT * FROM tbl");
while ($row = pdo_fetch_assoc($result)) {

Can be replaced with just an foreach iteration:

foreach ($result as $row) {

Or better yet a direct and complete array retrieval:

$result->fetchAll();
mysql_
pdo_query()

Unless you also introduce parameter binding or can utilize something else from the nicer API, it's a pointless switch. I hope it's portrayed simple enough to not further the discouragement to newcomers. (Education usually works better than prohibition.)

While it qualifies for the simplest-thing-that-could-possibly-work category, it's also still very experimental code. I just wrote it over the weekend. There's a plethora of alternatives however. Just google for PHP database abstraction and browse a little. There always have been and will be lots of excellent libraries for such tasks.

If you want to simplify your database interaction further, mappers like Paris/Idiorm are worth a try. Just like nobody uses the bland DOM in JavaScript anymore, you don't have to babysit a raw database interface nowadays.

Thanks. I'm mainly fond of the abstract pictograms visualizing parameterized queries. But I'll probably expand more on a later second conversion from pdo_query() to real PDO:: usage.

pdo_query("INSERT INTO pages VALUES (?,?,?,?,?)", $_POST);
pdo_query("INSERT INTO users VALUES (?, ?, ?), $_POST);  $_POST = array( 'username' => 'lawl', 'password' => '123', 'is_admin' => 'true');

@mario i'm thinking about using your pdo_* functions in a major legacy codebase. At the moment, i'm just experimenting, but already found a bug. Is there any way i can contribute to this project? Is 0.9.2 the latest version? THX!

@Tom Sure, albeit it's not maintained much (0.9.2 was the last), you can create a fossil account, add to the wiki or file a bug report (without registration IIRC).

mysql - Why shouldn't I use mysql_* functions in PHP? - Stack Overflow

php mysql database