PHP Command Line (CLI)

Yo Yogesh.M Updated 17 Oct 2026
6 min read ·Lesson 87 of 109
In this post

PHP Beyond the Web Server In simple terms: PHP is not limited to web pages. You can run PHP scripts directly in a terminal — to import data, send scheduled emails, clean up old files, run database mig

PHP Beyond the Web Server

In simple terms: PHP is not limited to web pages. You can run PHP scripts directly in a terminal — to import data, send scheduled emails, clean up old files, run database migrations, or build small tools. Frameworks rely on this constantly: php artisan migrate, php bin/console cache:clear, and composer install are all PHP command-line programs.

Technically: The CLI SAPI (Server API) is the php executable used in terminals. It differs from web SAPIs (PHP-FPM, Apache module): there are no HTTP requests or headers, output goes to the terminal, arguments arrive in $argv, the standard streams STDIN, STDOUT, and STDERR are available, max_execution_time defaults to 0 (unlimited), and it usually reads its own php.ini.


Useful php Commands

CommandPurpose
php script.php arg1 arg2Run a script with arguments
php -vShow the PHP version
php -mList loaded extensions
php -iShow the full configuration (like phpinfo() as text)
php --iniShow which php.ini files are loaded
php -l file.phpCheck a file for syntax errors ("lint")
php -r 'echo PHP_VERSION, PHP_EOL;'Run a short piece of code
php -aInteractive shell
php -S localhost:8000 -t publicStart the built-in development web server (see PHP Built-in Web Server)
php -d memory_limit=1G script.phpOverride a php.ini setting for one run
php -l src/Order.php
No syntax errors detected in src/Order.php

Running php -l on every changed file before committing (or in continuous integration) catches syntax errors before they reach a server.


Command-Line Arguments: $argv and $argc

<?php
// args.php
echo "Script: {$argv[0]}\n";
echo "Argument count: " . ($argc - 1) . "\n";

foreach (array_slice($argv, 1) as $index => $argument) {
    echo "  [" . ($index + 1) . "] $argument\n";
}
php args.php report.csv "Tamil Nadu" --verbose

Output

Script: args.php
Argument count: 3
  [1] report.csv
  [2] Tamil Nadu
  [3] --verbose

$argv[0] is the script name; the arguments follow. Quotes in the shell keep Tamil Nadu together as one argument. $argv and $argc are available in the global scope of CLI scripts (inside functions, use $_SERVER['argv']).


Parsing Options With getopt()

<?php
// greet.php
$options = getopt('', ['name:', 'times::', 'shout']);

if (!isset($options['name']) || !is_string($options['name']) || $options['name'] === '') {
    fwrite(STDERR, "Usage: php greet.php --name=NAME [--times=N] [--shout]\n");
    exit(1);
}

$times = (int) ($options['times'] ?? 1);
$message = "Hello, {$options['name']}!";

if (isset($options['shout'])) {
    $message = strtoupper($message);
}

for ($i = 0; $i < max(1, $times); $i++) {
    echo $message . "\n";
}

exit(0);
php greet.php --name=Asha --times=2 --shout
php greet.php
echo $?

Output

HELLO, ASHA!
HELLO, ASHA!
Usage: php greet.php --name=NAME [--times=N] [--shout]
1

How It Works

DefinitionMeaningExample
name:Required value--name=Asha or --name Asha
times::Optional value (must use =)--times=2
shoutFlag without value--shout (value false in the array)
  1. getopt() returns an array of the options that were given; the first argument ('') would define short options such as -n.
  2. Error messages go to STDERR, separate from normal output on STDOUT, so they remain visible even when the output is redirected to a file.
  3. exit(1) returns a non-zero exit code, which signals failure to shell scripts, cron, and CI tools. $? in the shell shows the exit code of the last command; 0 means success.

Reading Input: STDIN

CLI scripts can process data piped from other programs or files:

<?php
// sum.php — reads one number per line
$total = 0;
$lines = 0;

while (($line = fgets(STDIN)) !== false) {
    $line = trim($line);
    if ($line === '') {
        continue;
    }
    $total += (int) $line;
    $lines++;
}

echo "Lines: $lines, total: $total\n";
printf "10\n20\n12\n" | php sum.php
php sum.php < numbers.txt

Output (for the first command)

Lines: 3, total: 42

Reading line by line keeps memory use constant, so the same script can sum a file with millions of lines. For interactive questions, readline('Continue? [y/N] ') reads a line typed by the user.


Detecting the CLI and Making Executable Scripts

#!/usr/bin/env php
<?php
// bin/cleanup
if (PHP_SAPI !== 'cli') {
    http_response_code(404);
    exit;
}

$deleted = 0;
foreach (glob(__DIR__ . '/../storage/tmp/*') ?: [] as $file) {
    if (is_file($file) && filemtime($file) < time() - 86400) {
        unlink($file);
        $deleted++;
    }
}

fwrite(STDOUT, "Deleted $deleted temporary files\n");
chmod +x bin/cleanup
./bin/cleanup
  • The shebang line (#!/usr/bin/env php) lets the operating system run the file directly; PHP skips this first line.
  • The PHP_SAPI check ensures that a maintenance script placed in a web-accessible folder by mistake cannot be triggered through the browser. Better still, keep such scripts in bin/, outside the document root.

Scheduled Jobs With Cron

On Linux servers, cron runs CLI scripts on a schedule:

# crontab -e   (minute hour day month weekday command)
15 2 * * * /usr/bin/php /var/www/shop/bin/cleanup >> /var/log/shop/cleanup.log 2>&1
*/5 * * * * /usr/bin/php /var/www/shop/bin/send-queued-emails
  • Use absolute paths for PHP and the script; cron runs with a minimal environment and a different working directory.
  • Redirect output to a log file (>> file 2>&1) so errors are not lost.
  • Prevent overlapping runs of long jobs with a lock (for example, flock in the shell, or a lock file in PHP).
  • Frameworks offer schedulers (Laravel's task scheduling, Symfony Scheduler) that need only one cron entry.

Long-Running CLI Processes

Queue workers and daemons run for hours or days. They require extra care:

ConcernAdvice
Memory leaksMonitor memory_get_usage(); restart workers periodically (after N jobs)
Stale connectionsReconnect to the database after errors such as "server has gone away"
Static stateReset caches and static properties between jobs
SupervisionRun workers under a process manager (systemd, Supervisor) that restarts them
SignalsHandle SIGTERM gracefully with pcntl_signal() to finish the current job before stopping

For larger command-line applications, libraries such as Symfony Console provide argument parsing, help texts, colored output, progress bars, and testing tools.


Common Mistakes

Assuming Web Settings Apply to the CLI

Effect: Different php.ini, time zone, or extensions cause unexpected behavior.

Fix: Check with php --ini and configure the CLI explicitly.

Using Relative Paths in Scheduled Scripts

Effect: Files are not found when cron runs the script from another directory.

Fix: Build paths from __DIR__.

Printing Errors to STDOUT and Always Exiting With 0

Effect: Automation cannot detect failures.

Fix: Write errors to STDERR and use non-zero exit codes.

Leaving CLI Scripts Accessible via the Web

Effect: Anyone can trigger maintenance tasks.

Fix: Store them outside the document root and check PHP_SAPI.


Best Practices

  • Use the CLI for imports, maintenance, scheduled jobs, and developer tools.
  • Parse options with getopt() (or Symfony Console) and print usage help on invalid input.
  • Separate output (STDOUT) from errors (STDERR) and return meaningful exit codes.
  • Process input as streams to keep memory use constant.
  • Schedule jobs with cron using absolute paths, logging, and locks; supervise long-running workers.

Official reference: https://www.php.net/manual/en/features.commandline.php

0 Comments

Reviewed before they appear

No comments yet.

PHP
PHP Home PHP Switch PHP Match Alternative Syntax PHP Loops While Loop Do While Loop For Loop Foreach Loop Nested Loops Break Statement PHP Home PHP Intro PHP Install PHP Built-in Web Server PHP Syntax PHP Tags PHP and HTML PHP Comments PHP Multiline Comments PHP Variables Variables Scope PHP Casting Logical Operators Null Coalescing Operator Spaceship Operator Operator Precedence Continue Statement Modify Strings PHP If...Else...Elseif PHP If Modify Strings PHP If Operators PHP Functions Concatenate Strings PHP If...Else Slicing Strings User-defined Functions Slicing Strings PHP Shorthand if Escape Characters Default Argument Values PHP Nested if Pass by Reference String Interpolation Named Arguments PHP File Upload Variadic Functions Return Values Search in Strings Multibyte Strings Type Declarations in Functions PHP Numbers PHP Math PHP Floats PHP Random Numbers PHP Constants PHP Properties PHP Methods PHP Constructor Constructor Property Promotion PHP Cookies PHP Destructor PHP Access Modifiers Readonly Properties PHP Sessions PHP Inheritance Method Overriding PHP Filters The final Keyword CSRF Protection PHP Filters Advanced Session Security Secure Cookies PHP Magic Constants File Upload Security PHP Callback Functions PHP Operators Filesystem Security PHP JSON Arithmetic Operators Error Reporting in Production Hiding PHP Assignment Operators PHP Configuration (php.ini) Comparison Operators PHP Command Line (CLI) PHP Exceptions Increment / Decrement Operators Migrating to PHP 8 PHP Form Validation PHP Form Required PHP Form URL/E-mail Error Handling Form Input Sanitizing Escaping Output (htmlspecialchars) Custom Error Handler Checkbox, Radio and Select Inputs Sticky Forms PHP Form Complete PHP Date and Time Date Formatting Error Logging HTTP Headers and Redirects Output Buffering Sending Email PHP cURL Consuming REST APIs PHP Generators
Ask about this post
AI Ask about this post

Ask questions about PHP Command Line (CLI) and get answers drawn from it.

Signed-in readers only.