# PHP på kommandolinjen (CLI)

> PHP CLI forklaret: forskelle til webversionen, vigtige indstillinger som -l, -m og --ini, cronjobs, indbygget webserver og hvorfor php -v ofte vildleder.

Kilde: https://phpsos.de/da/php/php-cli/  
Status: 25.10.2026  
Udbyder: PHP SOS, PHP-nødhjælp og serversikkerhed. Akut hjælp på WhatsApp: https://wa.me/491736494914?text=Hej%20PHP%20SOS%2C%20vi%20har%20brug%20for%20hj%C3%A6lp%20med%20vores%20PHP-server.%20Firma%3A%20%E2%80%A6%20Website%3A%20%E2%80%A6

**Kort sagt:** PHP CLI (Command Line Interface) er PHP-varianten til kommandolinjen. Den udfører scripts uden webserver, f.eks. til cronjobs, Composer eller vedligeholdelsesopgaver. Den har egne standardværdier, ofte en egen php.ini og undertiden endda en anden version end websitet. Derfor er `php -v` intet pålideligt bevis for, at websitet er patchet efter PHP2Shell.

## Hvad er PHP CLI?

PHP-manualen nævner to hovedanvendelser af PHP: scripts til websites og scripts på kommandolinjen. Til det sidste findes en egen SAPI med navnet `cli`. Den kræver hverken webserver eller browser, kun PHP-fortolkeren. Ifølge manualen egner den sig især til opgaver, der regelmæssigt kører via cron under Linux eller via opgaveplanlæggeren under Windows.

Typiske eksempler i virksomhedens hverdag: natlige importer i shoppen, udsendelse af nyhedsbreve, rydning af caches, opdateringer via Composer eller kommandolinjeværktøjerne i CMS-systemer som WP-CLI eller Symfony-konsollen. Under Windows hedder filen `php.exe`, CGI-varianten `php-cgi.exe`.

I modsætning til PHP-FPM er CLI ikke en tjeneste. Hvert kald starter en ny proces, læser ifølge manualen konfigurationen på ny og slutter, når scriptet er færdigt. En genstart efter en opdatering er derfor ikke nødvendig. Undtagelser er langtkørende processer, der startes via CLI, f.eks. kø-workere i frameworks eller dæmoner under systemd eller Supervisor. De kører i dagevis med den én gang indlæste fortolker og skal efter en PHP-opdatering genstartes på samme måde som web-workere.

For direktionen og projektledelsen betyder det: Også baggrundsopgaver hører med i oversigten og i hver opdateringsplan.

## Hvordan adskiller CLI sig fra webversionen?

Ifølge manualen overskriver CLI nogle indstillinger fast. De kan ikke ændres via php.ini, kun under kørsel med `ini_set()`:

| Direktiv | Værdi i CLI | Begrundelse ifølge manualen |
|---|---|---|
| `html_errors` | fra | HTML-tags forstyrrer i terminalen |
| `implicit_flush` | til | output skal vises med det samme |
| `max_execution_time` | 0 (ubegrænset) | kommandolinjescripts kører ofte længe |
| `register_argc_argv` | til | scripts får altid `$argc` og `$argv` |
| `output_buffering` | fra | fast indkodet, bufferfunktioner kan stadig bruges |
| `max_input_time` | fra | CLI kender hverken GET, POST eller uploads |

En yderligere forskel: CLI skifter ikke til scriptets mappe. Den, der kalder `php -f ordner/skript.php` fra `/tmp`, arbejder fortsat i `/tmp`. Relative stier i cronjobs er derfor en hyppig fejlkilde.

Et lille script, der kun skal køre på kommandolinjen:

```php
<?php
if (PHP_SAPI !== 'cli') {
    http_response_code(403);
    exit('Nur für die Kommandozeile.');
}
$tage = (int) ($argv[1] ?? 30);
$grenze = time() - $tage * 86400;
$alt = 0;
foreach (glob(__DIR__ . '/cache/*.tmp') ?: [] as $datei) {
    if (filemtime($datei) < $grenze) { $alt++; }
}
fwrite(STDOUT, "Dateien älter als $tage Tage: $alt\n");
```

Kontrollen af `PHP_SAPI` forhindrer, at et vedligeholdelsesscript udløses via browseren, hvis det ved en fejl ligger i webmappen. Manualen anbefaler udtrykkeligt at kontrollere SAPI'en på denne måde frem for at stole på, at `$argv` findes.

## De vigtigste indstillinger i PHP CLI

De følgende indstillinger stammer fra indstillingsoversigten i PHP-manualen og er særligt nyttige for administratorer:

1. **`php -v`** viser CLI's versionsnummer.
2. **`php --ini`** viser, hvilke konfigurationsfiler der indlæses.
3. **`php -m`** opregner de indkompilerede og indlæste moduler.
4. **`php -i`** kalder `phpinfo()` og udskriver resultatet som tekst.
5. **`php -l datei.php`** kontrollerer kun syntaksen (lint). Siden PHP 8.3 også for flere filer på én gang.
6. **`php -r 'code'`** udfører kode direkte, uden `<?php`.
7. **`php -d name=wert`** sætter en INI-indstilling for dette kald.
8. **`php -n`** ignorerer php.ini fuldstændigt.
9. **`php --ri name`** viser konfigurationen for en udvidelse.

```bash
php --ini
php -m | grep -i -E "opcache|sodium|pdo"
php --ri session | grep upload_progress
php -l src/Controller.php src/Model.php
```

## Den indbyggede webserver: kun til udvikling

Med `php -S localhost:8000` starter CLI en lille webserver. Eksempeloutputtet i manualen nævner PHP 5.4.0 som udgangspunkt. Manualen er utvetydig: Serveren tjener udvikling, er ikke en fuldgyldig webserver og skal hverken køre i offentlige netværk eller i produktion. Kører den permanent på en server og kan nås udefra, er det et fund, I bør få bragt til ophør.

## CLI, cron og sikkerhed efter PHP2Shell

De kendte meddelelser om PHP2Shell nævner PHP-FPM, mod_php, php-cgi, FrankenPHP og LiteSpeed som berørte driftsformer. CLI behandler ingen forespørgsler fra nettet. For sikkerheden er den alligevel vigtig i tre henseender:

- **Forkert bevis:** `php -v` viser CLI-versionen. Websitet kan bruge en anden version, og distributioners backports ændrer ofte ikke det viste nummer. Hvordan I dokumenterer status korrekt, står under [Kontrollér PHP-version og patchstatus](https://phpsos.de/da/php2shell/php-version-pruefen/) og i indlægget [Hvorfor php -v viser det samme nummer](https://phpsos.de/da/blog/php-v-zeigt-alte-nummer/).
- **Persistens via cron:** Angribere bruger efter et indbrud gerne cronjobs, der regelmæssigt starter et PHP-script. Henvisninger til søgningen giver [Genkend skjulte cronjobs som bagdør](https://phpsos.de/da/blog/cronjobs-als-hintertuer/).
- **Samme pakke:** CLI stammer som regel fra den samme pakkekilde som PHP-FPM og hører med i opdateringen.

## Hvordan hjælper PHP SOS konkret?

- **Afstemme versioner:** Vi sammenligner CLI- og webstatus og dokumenterer, hvilken version jeres website virkelig leverer.
- **Kontrollere cronjobs:** Vi opregner alle planlagte PHP-opgaver for alle brugere og henfører dem til deres applikationer.
- **Sikre vedligeholdelsen:** Vi flytter vedligeholdelsesscripts ud af webmappen og sætter SAPI-kontroller.
- **Passe dem vedvarende:** I [sikkerhedsvedligeholdelsesaftalen](https://phpsos.de/da/leistungen/security-wartungsvertrag/) holder vi CLI, web-SAPI og cronjobs aktuelle sammen.


## Ofte stillede spørgsmål

**Viser php -v mit websites version?**  
Ikke nødvendigvis. php -v viser kommandolinjevariantens version. Websitet kan køre via en anden PHP-FPM-version eller et Apache-modul. For websitet tæller web-SAPI'ens status, som I finder via tjenesten eller en kortvarig kontrolfil.

**Hvorfor kører CLI-scripts uden tidsbegrænsning?**  
Ifølge PHP-manualen sætter CLI max_execution_time fast til 0, altså ubegrænset, fordi scripts på kommandolinjen ofte udfører lange opgaver. Køretiden kan begrænses via selve scriptet eller via værktøjer som timeout.

**Må jeg bruge den indbyggede webserver php -S i produktion?**  
Nej. Manualen beskriver den som en hjælp til udvikling, ikke som en fuldgyldig webserver, og fraråder brug i offentlige netværk og i produktion. Til live-systemer hører Apache, Nginx eller LiteSpeed med PHP-FPM foran.

**Er OPcache aktiv på kommandolinjen?**  
Som standard nej. opcache.enable_cli står ifølge manualen på 0. Til korte scripts giver cachen alligevel kun lidt, fordi hvert kald er en ny proces.

## Kilder

- [PHP-manualen: PHP på kommandolinjen](https://www.php.net/manual/en/features.commandline.php)
- [PHP-manualen: Forskelle ved CLI-SAPI'en](https://www.php.net/manual/en/features.commandline.differences.php)
- [PHP-manualen: CLI-indstillinger](https://www.php.net/manual/en/features.commandline.options.php)
- [PHP-manualen: Indbygget webserver](https://www.php.net/manual/en/features.commandline.webserver.php)
