FastCGI

O FastCGI

FastCGI je vylepšená verze CGI. CGI při každém požadavku načte program znovu z disku počítače a spustí. A to trvá dost dlouho. FastCGI přichází s jiným přístupem. Program se spustí jednou a pak ve smyčce obsluhuje jedno připojení za druhým.

Všechno co potřebujete k tomu, aby váš program mohl běžet ve smyčce a přijímat od serveru jedno spojení za druhým už pro vás bylo naprogramováno. Stačí, když si nainstalujete vývojový balíček FastCGI. V OpenSuSE se jmenuje FastCGI-devel, v Debianu libfcgi-dev. V jiné distribuci se zase může jmenovat jinak …

Když už máte FastCGI knihovnu nainstalovanou, můžete se hned pustit do prvního příkladu.

Důležitá věc při psaní FastCGI programu je použití hlavičkového souboru <fcgi_stdio.h>. Tento soubor redefinuje standardní knihovnu <stdio.h>. V souboru fcgi_stdio.h najdete podobné věci tomuto:

#undef  FILE
#define FILE     FCGI_FILE
#undef  stdin
#define stdin    FCGI_stdin

Redefinuje se v něm nejen FILE, stdin, stdout a stderr, ale i funkce printf(), fprintf(), fread(), fwrite() atd.

Až se budete učit C++ tak se dozvíže, že C++ na vstup a výstup používá objekty std::cin a std::cout atp. Tyto C++ vymoženosti ale knihovna fcgi_stdio.h neredefinuje, takže je v FastCGI programu nemůžete používat.

FastCGI program tedy používá jiné vstupní a výstupní proudy, ale díky <fcgi_stdio.h> to vypadá, jako by pracoval se standardním vstupem a výstupem.

Knihovna fcgi_stdio.h musí být includovaná jako poslední ze všech includovaných knihoven. Jakákoliv jiná knihovna totiž může v sobě includovat stdio.h a tím pádem všechny redefinice z fcgi_stdio.h zase redefinovat. Taková chyba se pak projeví zobrazením chyby v prohlížeči a hláškou Premature end of script headers v logu /var/log/apache/error.log.

V příkladech v této kapitole budu používat soubory common.h, common.c, html.h a html.c z kapitoly o CGI. Jediný rozdíl je v tom, že v souborech html.h a common.h includuju místo knihovny <stdio.h> knihovnu <fcgi_stdio.h>.

Příklad FastCGI programu

Takto vypadá ukázka FastCGI programu:

  1. /*------------------------------------------------*/
  2. /* 46fcgi/fcgi1.c                                 */
  3. #include "common.h"
  4. #include "html.h"
  5. #include <fcgi_stdio.h>
  6.  
  7. extern char **environ;
  8.  
  9. int main(int argc, char *argv[], char *env[])
  10. {
  11.     /* init */
  12.     static unsigned int i = 0;
  13.     /* work */
  14.     while (FCGI_Accept() >= 0) {
  15.         i++;
  16.         htmlStart("FastCGI 1");
  17.         printf("\t\t<p>Toto je %u-tý požadavek.</p>", i);
  18.         printEnvironmentVals();
  19.         printPostData();
  20.         htmlForm("post");
  21.         printAllEnvironmentVals(env);
  22.         htmlEnd();
  23.     }
  24.  
  25.     return 0;
  26. }
  27. /*------------------------------------------------*/

Typický FastCGI program začíná nějakou inicializací. Pak se spustí cyklus, který obsluhuje jednotlivé požadavky. O provádění cyklu se stará funkce FCGI_Accept().

Tato funkce vrací hodnotu >= 0, dokud chce server využívat služby programu. Pokud server nedostane na FCGI program dlouho žádný požadavek, rozhodne se jej ukončit. To udělá právě tím, že funkce FCGI_Accept() vrátí zápornou hodnotu.

Program inicializuje proměnnou i na 0 a pak ji při každém požadavku zvýší o 1. Když tedy v prohlížeči požádáte o spuštění tohoto FCGI programu, pokaždé by vám měl vrátit číslo o jedno větší.

Ovšem pozor, jak už jsem psal, pokud FCGI program dlouho nikdo nespustí, server jej ukončí a při dalším požadavku jej spustí na novo. Řada čísel tak zase začne od nuly. Server se taky může rozhodnout spustit FCGI program v několika vláknech, takže mohou běžet různé instance FCGI programu současně. Na to všechno je potřeba myslet při vývoji FCGI progarmu (o CGI programech nemluvě). Dejte si taky pozor na práci se sdílenými prostředky, jako jsou třeba soubory. Pokud server spustí více instancí FCGI programu a každá z nich se pokusí zapsat něco do stejného souboru, nejspíš si změny navzájem přepíšou. Tomu můžete zabránit použitím zamykání souborů. Nebo použijte databázi, která je na víceuživatelský přístup připravená.

Při překladu musíte překladači říct, v jakém adresáři najde soubor fcgi_stdio.h a připojit knihovnu fcgi. Mě se nainstaloval fcgi_stdio.h do adresáře /usr/include/fastcgi/, takže překlad může vypadat nějak takto:

$ clang -o fcgi1.cgi  fcgi1.c common.c html.c -lfcgi -I/usr/include/fastcgi/

Přeložený program můžete zkopírovat do ~/public_html/ a podívat se na výsledek na http://127.0.0.1/~username/fcgi1.cgi

FastCGI 1

Toto je 1-tý požadavek.

QUERY_STRING:

REQUEST_METHOD: GET

Jméno:
Příjmení:
HTTP_HOST=localhost
HTTP_USER_AGENT=Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Firefox/31.0
HTTP_ACCEPT=text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
HTTP_ACCEPT_LANGUAGE=cs,en-us;q=0.7,en;q=0.3
HTTP_ACCEPT_ENCODING=gzip, deflate
HTTP_DNT=1
HTTP_COOKIE=fontSize=large
HTTP_CONNECTION=keep-alive
HTTP_CACHE_CONTROL=max-age=0
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
SERVER_SIGNATURE=
Apache/2.4.6 (Linux/SUSE) Server at localhost Port 80

SERVER_SOFTWARE=Apache/2.4.6 (Linux/SUSE)
SERVER_NAME=localhost
SERVER_ADDR=::1
SERVER_PORT=80
REMOTE_HOST=localhost
REMOTE_ADDR=::1
DOCUMENT_ROOT=/srv/www/htdocs
REQUEST_SCHEME=http
CONTEXT_PREFIX=/~username
CONTEXT_DOCUMENT_ROOT=/home/username/public_html
SERVER_ADMIN=[no address given]
SCRIPT_FILENAME=/home/username/public_html/fcgi1.cgi
REMOTE_PORT=33514
GATEWAY_INTERFACE=CGI/1.1
SERVER_PROTOCOL=HTTP/1.1
REQUEST_METHOD=GET
QUERY_STRING=
REQUEST_URI=/~username/fcgi1.cgi
SCRIPT_NAME=/~username/fcgi1.cgi

Teď asi mačkáte jako blázni tlačítko refresh ve svém webovém prohlížeči a přemýšlíte, proč se vám pořád zobrazuzje Toto je 1-tý požadavek..
To proto, že se program nespouští jako FCGI, ale jen jako CGI. Funkce FCGI_Accept() se v takovém případě zachová vychytrale. Při prvním volání vrací hodnotu >=0 a při druhém zápornou hodnotu. Takže smyčka proběhne právě jednou.

Aby se program spustil jako FastCGI, musíte nejdříve nakonfiguraovat Apache.

Konfigurace Apache

Konfigurace bude probíhat podobně jako při konfiguraci Apache pro CGI.

Nejdříve si musíte nainstalovat modul fcgid. V OpenSuSE je to balíček apache2-mod_fcgi, v Debianu libapache2-mod-fcgid.

Druhým krokem je přidání řádku AddHandler fcgid-script .fcgi do souboru mod_userdir.conf, jako v případě konfigurace CGI, nebo do souboru mod_fcgid.conf (pak tato volba bude fungovat ve všech adresářích, nejen v public_html adresářích uživatelů).

A stejně jako se musel zapnout modul CGI, musí se zapnout i modul FCGI a restartovat Apache. Tj, například v OpenSuSE takto:

$ sudo /usr/sbin/a2enmod fcgid
$ sudo systemctl restart apache2
Server v Debianu restartujete pomocí příkazu /etc/init.d/apache2 restart.

Teď už stačí přejmenovat program fcgi1.cgi na fcgi1.fcgi a měli byste vidět, jak se hodnota v Toto je 1-tý požadavek. při každém znovunačtení stránky zvyšuje.

Tentokrát si ale můžete všimnou jiné podivnosti. Podívejte se na výpis všech proměnných prostředí. Kam zmizely? Vypisují se proměnné prostředí předané jako třetí argument funkce main. Ten ale ve FastCGI žádné proměnné nedostane (maximálně proměnnou PATH). Správně byste měli načítat proměnné prostředí z extern **environ;. Předejte tuto proměnnou funkci printAllEnvironmentVals() jako argument a všechny proměnné prostředí se zase vrátí :-).

qDecoder

V kaptiole o CGI jste viděli, jak jsou předávány uživatelem odeslaná data pomocí proměnných prostředí nebo standardního vstupu. A taky že se různými způsoby kódují. Knihovna qDecoder je tu od toho, aby vám s dekódováním těchto dat pomohla.

Knihovna qDecoder pracuje s CGI i FastCGI. Kromě parsování GET a POST dat (dat předaných v query stringu a ve standardním vstupu) umí pracovat i s cookies a vytvářet session. Cookies a session jsou pojmy vztahující se k programování webů, takže je tu nebudu dále rozebírat.

Instalace

qDecoder nejspíš jako balíček ve své linuxové distribuci nenajdete. Stáhněte si zdrojové kódy z githubu.

Rozbalte jej do nějakého adrsáře. Já jsem jej rozbalil do qdecoder12_0_5 (tento adresář je i součástí zdrojových kódů ke stažení). Přejděte do něj a nejdříve spusťte konfiguraci. Protože budu ukazovat qDecoder s FastCGI, musíte konfiguračnímu skriptu předat argument s cestou ke knihovně fcgi_stdio.h: --enable-fastcgi=/usr/include/fastcgi/. Dále spusťte příkazy make a jako root make install.

qdecoder12_0_5$ ./configure --enable-fastcgi=/usr/include/fastcgi/ --enable-debug
...
qdecoder12_0_5$ make
...
qdecoder12_0_5$ sudo make install
...

Pozor! V Debianu jsem musel před make install upravit v souboru src/Makefile cesty k programům mkdir a dalším. Jsou tam totiž cesty zapsané jako /usr/bin/mkdir, ale v Debianu je mkdir (a další programy) v adresáři /bin/.

Příkaz make install přesune knihovnu libqdecoder.so a liqdecoder.a do adresáře /usr/local/lib64/ a hlavičkový soubor qdecoder.h do adresáře /usr/local/include/. Aby šlo program s touto knihovnou přeložit, musí se nejdříve spustit ldconfig, viz sdílené knihovny.

V 32 bitové verzi Linuxu to asi nebude adresář /usr/local/lib64/, ale nějaký jiný.

V Debianu byste měli nejdříve přidat adresár /usr/local/lib64 do souboru /etc/ld.so.conf.d/qdecoder.conf a pak spustit ldconfig.

$ echo "/usr/local/lib64" >> /etc/ld.so.conf.d/qdecoder.conf
$ ldconfig

Načítání proměnných z POST a GET

Teď už by mělo být všechno připravno k tomu, abyste si mohli qDecoder vyzkoušet.

První je v příkladu volána funkce qcgireq_parse().

qentry_t* qcgireq_parse(qentry_t * request, Q_CGI_T method);

Funkce alokuje paměť pro strukturu qentry_t a vrátí na ni ukazatel. Prvním argumentem může být odkaz na tuto strukturu, pokud voláte qcgireq_parse() podruhé a chcete tuto paměť „recyklovat“. Při prvním volání je tedy, logicky, vždy NULL.

Druhý argument určuje, odkud se budou parzovat proměnné. 0 znamená, že se budou parsovat nejdříve z COOKIES. Pokud se tam proměnná nenajde, bude se parsovat z POST a když ani tam se nenajde, bude se parsovat z GET.

Q_CGI_T konstanty
Q_CGI_ALL nebo 0Proměnná se hledá v pořadí COOKIE, POST, GET
Q_CGI_COOKIEProměnná se hledá jen v COOKIES
Q_CGI_POSTProměnná se hledá jen v POST
Q_CGI_GETProměnná se hledá jen v GET

Struktura qentry_t obsahuje spousty ukazatelů na funkce, které můžete používat pro dotazovanání se na dekódované proměnné. Nejčastěji asi budete používat getstr(), viz příklad:

  1. /*------------------------------------------------*/
  2. /* 46fcgi/qdecoder1.c                             */
  3. #include "common.h"
  4. #include "html.h"
  5. #include <qdecoder.h>
  6. #include <fcgi_stdio.h>
  7.  
  8. extern char **environ;
  9.  
  10. int main(int argc, char *argv[], char *env[])
  11. {
  12.     static unsigned int i = 0;
  13.     while (FCGI_Accept() >= 0) {
  14.         i++;
  15.         htmlStart("qDecoder 1");
  16.         printf("\t\t<p>Toto je %u-tý požadavek.</p>", i);
  17.         printEnvironmentVals();
  18.         /* qDecoder */
  19.         qentry_t *req = qcgireq_parse(NULL, 0);
  20.         char *name = (char *)req->getstr(req, "jmeno", false);
  21.         char *surname = (char *)req->getstr(req, "prijmeni", false);
  22.         printf("\t\t<p>qdecoder: name = '%s', surname = '%s'</p>\n",
  23.                name ? name : "(null)", surname ? surname : "(null)");
  24.         req->free(req);
  25.         /* konec qDecoder */
  26.         printPostData();
  27.         htmlForm("post");
  28.         printAllEnvironmentVals(environ);
  29.         htmlEnd();
  30.     }
  31.     return 0;
  32. }
  33.  
  34. /*------------------------------------------------*/

Při překladu přidejte fcgi a qdecoder knihovny a cestu k hlavičkovým souborům:

$ gcc -o qdecoderer1.fcgi qdecoder1.c html.c common.c -lfcgi -lqdecoder -I/usr/include/fastcgi/

Funkce req->getstr() má jako první argument strukturu qentry_t, jako druhý argument název proměnné, jejíž hodnotu chcete získat (z COOKIE, POST nebo GET – to záleží na druhém parametru qcgireq_parse()).
Pokud je třetí argument true, bude pro výsledek alokována nová paměť, kterou pak musíte sami uvolnit pomocí free(). Pokud je třetí parametr false, stačí na konci zavolat req->free(req) pro uvolnění paměti struktury qentry_t (to by se mělo volat v každém případě).
Ve vícevláknovém prostředí by měl být třetí argument vždy true.

Zkuste si spustit tento příklad z url: http://localhost/~username/qdecoder1.fcgi?jmeno=Julius. Uvidíte, že qDecoder získá jméno z query stringu (neboli GET požadavku). Když pak odešlete formulář (POSTem), který má input se jménem jmeno, vezme qDecoder hodnotu proměnné jmeno z POSTu.

Načítání souboru z POST

Druhý příklad zobrazí obsah odeslaného (textového) souboru. Tentokrát je nastaveno, že se data budou číst jenom z POSTu.
Formulář odesílá soubor v inputu se jménem soubor. Všiměte si, jaké používa qDecoder názvy proměnných pro získání informací o souboru (např. soubor.length pro získání délky souboru).

  1. /*------------------------------------------------*/
  2. /* 46fcgi/qdecoder2.c                             */
  3. #include "common.h"
  4. #include "html.h"
  5. #include <qdecoder.h>
  6. #include <fcgi_stdio.h>
  7.  
  8. int main(int argc, char *argv[], char *env[])
  9. {
  10.     static unsigned int i = 0;
  11.     while (FCGI_Accept() >= 0) {
  12.         i++;
  13.         htmlStart("qDecoder 2");
  14.         printf("\t\t<p>Toto je %u-tý požadavek.</p>\n", i);
  15.         /* qDecoder */
  16.         qentry_t *req  = qcgireq_parse(NULL, Q_CGI_POST);
  17.         char *file     = req->getstr(req, "soubor", false);
  18.         int  length    = req->getint(req, "soubor.length");
  19.         char *filename = req->getstr(req, "soubor.filename", false);
  20.         char *contenttype = req->getstr(req, "soubor.contenttype", false);
  21.         if(!filename) {
  22.             printf("\t\t<p>Soubor nebyl nahrán</p>\n");
  23.         } else {
  24.             printf("\t\t<p>Byl nahrán soubor %s délky %i bajtů typu %s.</p>\n",
  25.                     filename, length, contenttype);
  26.             printf("\t\t<h3>Obsah souboru: </h3>\n");
  27.             printf("\t\t<pre>%*s</pre>\n", length, file);
  28.         }
  29.  
  30.         req->free(req);
  31.         /* konec qDecoder */
  32.         htmlFormWithFile();
  33.         htmlEnd();
  34.     }
  35.     return 0;
  36. }
  37.  
  38. /*------------------------------------------------*/

Jediná nová funkce, kterou jsem v tomto příkladu použil, je req->getint() pro získání proměnné soubor.length jako čísla.

Příklad vypíše nahraný soubor na obrazovku. To bude fungovat jen v případě textových souborů, binární soubory samozřejmě nemůžete tisknout pomocí printf(). Funkce printf() zastaví tisk u prvního nulového bajtu, kterých je v binárních souborech obvykle hodně.

Po odeslání souboru hello-world.txt, jehož obsahem je jediná věta Hello World! může výsledek vypadat takto:

qDecoder 2

Toto je 5-tý požadavek.

Byl nahrán soubor hello-world.txt délky 13 bajtů typu text/plain.

Obsah souboru:

Hello World!
Jméno:
Příjmení:
Soubor:

Tímto způsobem nahrává qDecoder celý soubor do paměti (do proměnné soubor), což v případě velkých souborů není moc praktické. To můžete změnit voláním funkce qcgireq_setoption(), kterou přepnete do něčeho, čemu autor qDecoderu říká file mode. Soubor pak bude uložen přímo na disk.

Q_ENTRY *req = qcgireq_setoption(NULL, true, "/tmp", 86400);
req = qcgireq_parse(req, Q_CGI_POST);
/* kde je soubor uložen? */
char *savepath = req->getstr(req, "soubor", false);
int  length    = req->getint(req, "soubor.length");
...
req->free(req);

Soubor máte na disku, víte že cesta k němu je savepath, takže si s ním už můžete dělat co chcete.

CURL

V kaptiole o CGI jste mohli vidět, jak je query string kódován pomocí % sekvencí. Například Žluťoučký kůň se zakóduje jako %C5%BDlu%C5%A5ou%C4%8Dk%C3%BD+k%C5%AF%C5%88. Knihovana qDecoder vám tuto sekvenci znaků dekóduje zase jako Žluťoučký kůň. Co ale když chcete použít query string v odkazu v HTML dokumentu, který generujete? Jak převedete Žluťoučký kůň na zakódovaný query string? K tomu vám už qDecoder nepomůže. Ale pomůže vám knihovna CURL.

Knihovna CURL je velmi známá, oblíbená a šikovná knihovna, která se používá především pro posílání dat přes HTTP protokol. Teď mě tak napadá, že kdybych vám o ní řekl už na začátku, mohli jste si ušetřit práci s psaním vlastního HTTP klienta :-P.

CURL toho umí ale mnohem, mnohem víc. Dokáže komunikovat nejen pomocí HTTP, ale i HTTPS (šifrovaná verze), FTP, POP3 a SMTP (čtení a posílání emailů), umí se přihlašovat pomocí jména a hesla k různým službám atd.

CURL není jen knihovna (libcurl), ale i program curl, který můžete spouštět z příkazové řádky.

Já vám tu nebudu popisovat ani program curl, ani knihovnu libcurl nějak do hloubky, jen vám ukáži jak použít funkci curl_easy_escape() k zakódování hodnoty v query stringu. Snad to bude pro vás takový odrazový můstek pro další zkoumání CURL.

Instalace libcurl

Tuto knihovnu budete mít v balíčcích své oblíbené linuxové distribuce. V OpenSuSE si nainstalujte libcurl-devel. V Debianu máte na výběr ze tří možností: libcurl4-openssl-dev, libcurl4-nss-dev a libcurl4-gnutls-dev. Tyto balíčky se liší v použité implementaci TLS (šifrování). Pro použití funkce curl_easy_escape() je úplně nepodstatné, který balíček s vyberete. Já dávám přednost libcurl4-openssl-dev.

Použití libcurl

První, co musíte udělat, je inicializovat CURL. K tomu se používají funkce curl_global_init() a curl_easy_init().

CURLcode curl_global_init(long flags);

Parametr flags může být:

flagsVýznam
CURL_GLOBAL_ALLInicializuje všechno co jde, kromě CURL_GLOBAL_ACK_EINTR
CURL_GLOBAL_SSLInicializuje jen SSL
CURL_GLOBAL_WIN32Inicializuje Win32 sokety (jen we Windows)
CURL_GLOBAL_NOTHINGNeinicalizuje nic extra.
CURL_GLOBAL_DEFAULTDoporučené „rozumné“ nastavení. Inicializuje SSL i Win32. V tuto chvíli je to ekvivalentní flagu CURL_GLOBAL_ALL
CURL_GLOBAL_ACK_EINTRBez tohoto natavení CURL ignoruje signál EINTR a čeká, dokud nevyprchá timeout (při čekání na nějaká data z internetu atp.)

Protože chci v příkladu použít jen curl_easy_escape(), vystačím si s flagem CURL_GLOBAL_NOTHING.

CURL *curl_easy_init(void);

Tato funkce vrátí odkaz na strukturu CURL, kterou většina curl funkcí vyžaduje jako argument.

Struktura musí být po použití uvolněna funkcí curl_easy_cleanup(), aby nedocházelo k únikům paměti.

void curl_easy_cleanup(CURL * handle);

No a pro escapování hodnoty do query stringu se použije curl_easy_escape():

char *curl_easy_escape(CURL * curl , char * url, int length);

Parametr length určuje délku parametru url (což je řetězec, který se bude escapovat). Pokud necháte length 0, funkce curl_easy_escape() použije pro zjištění délky url funkci strlen().

Vrácené pole znaků se musí uvolnit funkcí curl_free():

void curl_free(char * ptr);

Příklad:

  1. /*------------------------------------------------*/
  2. /* 46fcgi/curl1.c                                 */
  3. #include "common.h"
  4. #include "html.h"
  5. #include <qdecoder.h>
  6. #include <curl/curl.h>
  7. #include <fcgi_stdio.h>
  8.  
  9. extern char **environ;
  10.  
  11. int main(int argc, char *argv[])
  12. {
  13.     static unsigned int i = 0;
  14.     while (FCGI_Accept() >= 0) {
  15.         i++;
  16.         htmlStart("CURL 1");
  17.         printf("\t\t<p>Toto je %u-tý požadavek.</p>", i);
  18.         printEnvironmentVals();
  19.         /* qecoder */
  20.         qentry_t *req = qcgireq_parse(NULL, Q_CGI_POST);
  21.         char *name = (char *)req->getstr(req, "jmeno", false);
  22.         char *surname = (char *)req->getstr(req, "prijmeni", false);
  23.         printf("\t\t<p>qdecoder: name = '%s', surname = '%s'</p>\n",
  24.                name ? name : "(null)", surname ? surname : "(null)");
  25.         /* curl */
  26.         if (name && surname) {
  27.             curl_global_init(CURL_GLOBAL_NOTHING);
  28.             CURL *curl = curl_easy_init();
  29.             char *escName = curl_easy_escape(curl, name, 0);
  30.             char *escSurname = curl_easy_escape(curl, surname, 0);
  31.             printf("\t\t<p>curl = 'jmeno=%s&prijmeni=%s'</p>\n",
  32.                    escName ? escName : "",
  33.                    escSurname ? escSurname : "");
  34.             curl_free(escName);
  35.             curl_free(escSurname);
  36.             curl_easy_cleanup(curl);
  37.         }
  38.         /* konec curl */
  39.         printPostData();
  40.         htmlForm("post");
  41.         htmlEnd();
  42.     }
  43.     return 0;
  44. }
  45.  
  46. /*------------------------------------------------*/

Při překladu programu můžete využít skript curl-config pro získání parametrů s knihovnou a adresářem k hlavičkovým souborům CURL:

$ clang -o curl1.fcgi curl1.c html.c common.c -lqdecoder -lfcgi `curl-config --cflags --libs` -I/usr/include/fastcgi/

Výstup, po odeslání formuláře se jménem Žluťoučký kůň bude vypadat takto:

CURL 1

Toto je 2-tý požadavek.

QUERY_STRING:

REQUEST_METHOD: POST

qdecoder: name = 'Žluťoučký kůň', surname = ''

curl = 'jmeno=%C5%BDlu%C5%A5ou%C4%8Dk%C3%BD%20k%C5%AF%C5%88&prijmeni='

		
Jméno:
Příjmení:

CURL pochopitelně můžete používat v jakémkoliv programu, nejen CGI. Pokud se chcete o knihovně CURL dozvědět více, začněte tutoriálem.

PHP

Pokud vás zajímá PHP, můžete se podívat na to, jak nastavit PHP jako FastCGI. Pokud vás nezajímá, tak na to nekoukejte :-).

Komentář Hlášení chyby
Created: 6.10.2014
Last updated: 4.7.2017
Tato stánka používá ke svému běhu cookies, díky kterým je možné monitorovat, co tu provádíte (ne že bych to bez cookies nezvládl). Také vás tu bude špehovat google analytics. Jestli si myslíte, že je to problém, vypněte si cookies ve vašem prohlížeči, nebo odejděte a už se nevracejte :-). Prohlížením tohoto webu souhlasíte s používáním cookies. Dozvědět se více..