(←Membuat halaman berisi 'Untuk melakukan instalasi perl Dancer, berikut adalah langkah-langkahnya: ===Install Perl minimal versi 5.24=== Silakan anda buka tiket untuk meminta staf kami mengi...') |
|||
Baris 19: | Baris 19: | ||
===Instalasi Dancer=== | ===Instalasi Dancer=== | ||
− | Gunakan perintah berikut untuk menginstall Dancer: | + | Gunakan perintah berikut untuk menginstall Dancer: |
+ | |||
+ | <source lang="bash"> | ||
+ | $ cpanm --force Dancer2 FCGI FCGI::ProcManager` | ||
+ | </source> | ||
===Membuat Skeleton Aplikasi Dancer=== | ===Membuat Skeleton Aplikasi Dancer=== | ||
− | Gunakan perintah berikut untuk membuat skeleton aplikasi dancer: | + | Gunakan perintah berikut untuk membuat skeleton aplikasi dancer: |
+ | |||
+ | <source lang="bash"> | ||
+ | $ dancer2 -a MyApp && cd MyApp` | ||
+ | </source> | ||
+ | |||
+ | ===Menjalankan Aplikasi Dancer=== | ||
+ | |||
+ | Untuk menjalankan aplikasi Dancer tersebut, gunakan perintah: | ||
+ | |||
+ | <source lang="bash"> | ||
+ | $ plackup s FCGI --listen $HOME/myapp.sock myapp.psgi | ||
+ | </source> | ||
+ | |||
+ | Anda juga perlu mengganti permission socket agar dapat diakses oleh webserver: | ||
+ | |||
+ | <source lang="bash"> | ||
+ | $ chmod 777 $HOME/myapp.sock | ||
+ | </source> | ||
+ | |||
+ | ===Aktifkan Extension sockets di PHP=== | ||
+ | |||
+ | Masuk ke [[Control Panel]], lalu ke menu Language - PHP. Dan edit konfigurasi untuk versi PHP yang digunakan. Tambahkan baris berikut ke konfigurasi tersebut: | ||
+ | |||
+ | <source lang="ini"> | ||
+ | extension=sockets.so | ||
+ | </source> | ||
+ | |||
+ | ===Buat Client FastCGI=== | ||
+ | |||
+ | Gunakan script ini untuk membuat client FastCGI: | ||
+ | |||
+ | <source lang="php"> | ||
+ | <?php | ||
+ | /* | ||
+ | * Configure these by adding two define()s to spawn-fcgi.conf.php: | ||
+ | * | ||
+ | * SPAWN should be a command to spawn a fastcgi process on a socket | ||
+ | * SOCKET should point to the socket | ||
+ | * | ||
+ | * the example SPAWN is a web.py app (see demo.py) | ||
+ | */ | ||
+ | |||
+ | define("SOCKET", '/home/xxx/myapp.sock'); | ||
+ | define("SPAWN", '-'); | ||
+ | |||
+ | |||
+ | /* | ||
+ | * Spawn-FCGI.php: A script to translate PHP requests into FastCGI | ||
+ | * requests, thus allowing hosting of FastCGI apps (good) on any | ||
+ | * PHP-compatible web host (cheap, common). | ||
+ | * | ||
+ | * This is almost a direct port of Flup's FastCGI test harness, | ||
+ | * flup_fcgi_client.py (c) 2006 Allan Saddi <allan@saddi.com> + | ||
+ | * 2011 Vladimir Rusinov <vladimir@greenmice.info> | ||
+ | * | ||
+ | * Modified to take request data from the environment rather than | ||
+ | * from function parameters. | ||
+ | * | ||
+ | * PHP port + modifications (c) 2012 Shish <webmaster@shishnet.org> | ||
+ | * | ||
+ | * | ||
+ | * Redistribution and use in source and binary forms, with or without | ||
+ | * modification, are permitted provided that the following conditions | ||
+ | * are met: | ||
+ | * 1. Redistributions of source code must retain the above copyright | ||
+ | * notice, this list of conditions and the following disclaimer. | ||
+ | * 2. Redistributions in binary form must reproduce the above copyright | ||
+ | * notice, this list of conditions and the following disclaimer in the | ||
+ | * documentation and/or other materials provided with the distribution. | ||
+ | * | ||
+ | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | ||
+ | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
+ | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
+ | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | ||
+ | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
+ | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
+ | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
+ | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
+ | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
+ | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||
+ | * SUCH DAMAGE. | ||
+ | */ | ||
+ | |||
+ | |||
+ | /* | ||
+ | * FastCGI constants | ||
+ | */ | ||
+ | define('FCGI_LISTENSOCK_FILENO', 0); | ||
+ | |||
+ | define('FCGI_HEADER_LEN', 8); | ||
+ | |||
+ | define('FCGI_VERSION_1', 1); | ||
+ | |||
+ | define('FCGI_BEGIN_REQUEST', 1); | ||
+ | define('FCGI_ABORT_REQUEST', 2); | ||
+ | define('FCGI_END_REQUEST', 3); | ||
+ | define('FCGI_PARAMS', 4); | ||
+ | define('FCGI_STDIN', 5); | ||
+ | define('FCGI_STDOUT', 6); | ||
+ | define('FCGI_STDERR', 7); | ||
+ | define('FCGI_DATA', 8); | ||
+ | define('FCGI_GET_VALUES', 9); | ||
+ | define('FCGI_GET_VALUES_RESULT', 10); | ||
+ | define('FCGI_UNKNOWN_TYPE', 11); | ||
+ | define('FCGI_MAXTYPE', FCGI_UNKNOWN_TYPE); | ||
+ | |||
+ | define('FCGI_NULL_REQUEST_ID', 0); | ||
+ | |||
+ | define('FCGI_KEEP_CONN', 1); | ||
+ | |||
+ | define('FCGI_RESPONDER', 1); | ||
+ | define('FCGI_AUTHORIZER', 2); | ||
+ | define('FCGI_FILTER', 3); | ||
+ | |||
+ | define('FCGI_REQUEST_COMPLETE', 0); | ||
+ | define('FCGI_CANT_MPX_CONN', 1); | ||
+ | define('FCGI_OVERLOADED', 2); | ||
+ | define('FCGI_UNKNOWN_ROLE', 3); | ||
+ | |||
+ | define('FCGI_MAX_CONNS', 'FCGI_MAX_CONNS'); | ||
+ | define('FCGI_MAX_REQS', 'FCGI_MAX_REQS'); | ||
+ | define('FCGI_MPXS_CONNS', 'FCGI_MPXS_CONNS'); | ||
+ | |||
+ | # SHIT: PHP needs different patterns for encode and decode | ||
+ | define('FCGI_Header', 'CCnnCx'); | ||
+ | define('FCGI_Header2', 'Cversion/Ctype/nrequestId/ncontentLength/CpaddingLength/x'); | ||
+ | define('FCGI_BeginRequestBody', 'nCx5'); | ||
+ | define('FCGI_EndRequestBody', 'NCx3'); | ||
+ | define('FCGI_UnknownTypeBody', 'Cx7'); | ||
+ | |||
+ | # SHIT: PHP has no calcsize; so we calculate by hand and hardcode the result | ||
+ | define('FCGI_BeginRequestBody_LEN', 8); # calcsize(FCGI_BeginRequestBody)); | ||
+ | define('FCGI_EndRequestBody_LEN', 8); # calcsize(FCGI_EndRequestBody)); | ||
+ | define('FCGI_UnknownTypeBody_LEN', 8); # calcsize(FCGI_UnknownTypeBody)); | ||
+ | |||
+ | /* | ||
+ | * Decodes a name/value pair. | ||
+ | * | ||
+ | * The number of bytes decoded as well as the name/value pair | ||
+ | * are returned. | ||
+ | */ | ||
+ | function decode_pair($s, $pos=0) { | ||
+ | $nameLength = ord($s[$pos]); | ||
+ | if($nameLength & 128) { | ||
+ | $nameLength = unpack('N', substr($s, $pos, 4)); | ||
+ | $nameLength = $nameLength[0] & 0x7fffffff; | ||
+ | $pos += 4; | ||
+ | } | ||
+ | else { | ||
+ | $pos += 1; | ||
+ | } | ||
+ | |||
+ | $valueLength = ord($s[$pos]); | ||
+ | if($valueLength & 128) { | ||
+ | $valueLength = unpack('N', substr($s, $pos, 4)); | ||
+ | $valueLength = $valueLength[0] & 0x7fffffff; | ||
+ | $pos += 4; | ||
+ | } | ||
+ | else { | ||
+ | $pos += 1; | ||
+ | } | ||
+ | |||
+ | $name = substr($s, $pos, $nameLength); | ||
+ | $pos += $nameLength; | ||
+ | $value = substr($s, $pos, $valueLength); | ||
+ | $pos += $valueLength; | ||
+ | |||
+ | return array($pos, array($name, $value)); | ||
+ | } | ||
+ | |||
+ | /* | ||
+ | * Encodes a name/value pair. | ||
+ | * | ||
+ | * The encoded string is returned. | ||
+ | */ | ||
+ | function encode_pair($name, $value) { | ||
+ | $nameLength = strlen($name); | ||
+ | if($nameLength < 128) { | ||
+ | $s = chr($nameLength); | ||
+ | } | ||
+ | else { | ||
+ | $s = pack('N', $nameLength | 0x80000000); | ||
+ | } | ||
+ | |||
+ | $valueLength = strlen($value); | ||
+ | if($valueLength < 128) { | ||
+ | $s .= chr($valueLength); | ||
+ | } | ||
+ | else { | ||
+ | $s .= pack('N', $valueLength | 0x80000000); | ||
+ | } | ||
+ | |||
+ | return $s . $name . $value; | ||
+ | } | ||
+ | |||
+ | function spawn() { | ||
+ | #print "Spawning new FastCGI daemon\n"; | ||
+ | $r = shell_exec(SPAWN); | ||
+ | } | ||
+ | |||
+ | /* | ||
+ | * A FastCGI Record. | ||
+ | * | ||
+ | * Used for encoding/decoding records. | ||
+ | */ | ||
+ | class Record { | ||
+ | function __construct($type=FCGI_UNKNOWN_TYPE, $requestId=FCGI_NULL_REQUEST_ID) { | ||
+ | $this->version = FCGI_VERSION_1; | ||
+ | $this->type = $type; | ||
+ | $this->requestId = $requestId; | ||
+ | $this->contentLength = 0; | ||
+ | $this->paddingLength = 0; | ||
+ | $this->contentData = ''; | ||
+ | } | ||
+ | |||
+ | /* | ||
+ | * Attempts to receive length bytes from a socket, blocking if necessary. | ||
+ | * (Socket may be blocking or non-blocking.) | ||
+ | */ | ||
+ | function _recvall($sock, $length) { | ||
+ | $dataList = array(); | ||
+ | $recvLen = 0; | ||
+ | while($length) { | ||
+ | $d = socket_recv($sock, $data, $length, null); | ||
+ | if($d === false) { | ||
+ | $r = array($sock); | ||
+ | $w = array(); | ||
+ | $x = array(); | ||
+ | socket_select($r, $w, $x, NULL); | ||
+ | continue; | ||
+ | } | ||
+ | if(!$data) { | ||
+ | break; | ||
+ | } | ||
+ | $dataList[] = $data; | ||
+ | $dataLen = strlen($data); | ||
+ | $recvLen += $dataLen; | ||
+ | $length -= $dataLen; | ||
+ | } | ||
+ | return array(implode('', $dataList), $recvLen); | ||
+ | } | ||
+ | |||
+ | /* | ||
+ | * Read and decode a Record from a socket. | ||
+ | */ | ||
+ | function read($sock) { | ||
+ | try { | ||
+ | $parts = $this->_recvall($sock, FCGI_HEADER_LEN); | ||
+ | $header = $parts[0]; | ||
+ | $length = $parts[1]; | ||
+ | } | ||
+ | catch(Exception $e) { | ||
+ | throw new EOFError(); | ||
+ | } | ||
+ | |||
+ | if($length < FCGI_HEADER_LEN) { | ||
+ | throw new EOFError(); | ||
+ | } | ||
+ | |||
+ | $parts = unpack(FCGI_Header2, $header); | ||
+ | $this->version = $parts['version']; | ||
+ | $this->type = $parts['type']; | ||
+ | $this->requestId = $parts['requestId']; | ||
+ | $this->contentLength = $parts['contentLength']; | ||
+ | $this->paddingLength = $parts['paddingLength']; | ||
+ | |||
+ | if($this->contentLength) { | ||
+ | try { | ||
+ | $parts = $this->_recvall($sock, $this->contentLength); | ||
+ | $this->contentData = $parts[0]; | ||
+ | $length = $parts[1]; | ||
+ | } | ||
+ | catch(Exception $e) { | ||
+ | throw new EOFError(); | ||
+ | } | ||
+ | |||
+ | if($length < $this->contentLength) { | ||
+ | throw new EOFError(); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | if($this->paddingLength) { | ||
+ | try { | ||
+ | $this->_recvall($sock, $this->paddingLength); | ||
+ | } | ||
+ | catch(Exception $e) { | ||
+ | throw new EOFError(); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | /* | ||
+ | * Writes data to a socket and does not return until all the data is sent. | ||
+ | */ | ||
+ | function _sendall($sock, $data) { | ||
+ | $length = strlen($data); | ||
+ | while($length) { | ||
+ | $sent = socket_send($sock, $data, strlen($data), 0); | ||
+ | if($sent === FALSE) { | ||
+ | $errorcode = socket_last_error(); | ||
+ | #if($errorcode == 107) { # ENOTCONN | ||
+ | # spawn(); | ||
+ | # continue; | ||
+ | #} | ||
+ | #else if($e[0] == errno.EAGAIN) { | ||
+ | # #select.select([], [sock], []) | ||
+ | # continue; | ||
+ | #} | ||
+ | #else { | ||
+ | $errormsg = socket_strerror($errorcode); | ||
+ | die("Couldn't write to socket: [$errorcode] $errormsg"); | ||
+ | #} | ||
+ | } | ||
+ | $data = substr($data, $sent); | ||
+ | $length -= $sent; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | /* | ||
+ | * Encode and write a Record to a socket. | ||
+ | */ | ||
+ | function write($sock) { | ||
+ | $this->paddingLength = -$this->contentLength & 7; | ||
+ | |||
+ | $header = pack(FCGI_Header, $this->version, $this->type, | ||
+ | $this->requestId, $this->contentLength, | ||
+ | $this->paddingLength); | ||
+ | $this->_sendall($sock, $header); | ||
+ | if($this->contentLength) { | ||
+ | $this->_sendall($sock, $this->contentData); | ||
+ | } | ||
+ | if($this->paddingLength) { | ||
+ | $this->_sendall($sock, str_repeat("\x00", $this->paddingLength)); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function _fcgiParams($sock, $requestId, $params) { | ||
+ | $rec = new Record(FCGI_PARAMS, $requestId); | ||
+ | $data = array(); | ||
+ | foreach($params as $name => $value) { | ||
+ | $data[] = encode_pair($name, $value); | ||
+ | } | ||
+ | $data = implode('', $data); | ||
+ | $rec->contentData = $data; | ||
+ | $rec->contentLength = strlen($data); | ||
+ | $rec->write($sock); | ||
+ | } | ||
+ | |||
+ | function connect() { | ||
+ | $sock = socket_create(AF_UNIX, SOCK_STREAM, 0); | ||
+ | |||
+ | $connected = false; | ||
+ | $errors = 0; | ||
+ | while(!$connected && $errors < 5) { | ||
+ | $connected = @socket_connect($sock, SOCKET); | ||
+ | if($connected === FALSE) { | ||
+ | $errorcode = socket_last_error(); | ||
+ | # no socket, or first connection refusal | ||
+ | if($errorcode == 2 || ($errorcode == 111 && $errors == 0)) { | ||
+ | spawn(); | ||
+ | } | ||
+ | # ECONNREFUSED; we started a process but it isn't running yet | ||
+ | else if($errorcode == 111) { | ||
+ | sleep(1); | ||
+ | $errors++; | ||
+ | } | ||
+ | else { | ||
+ | $errormsg = socket_strerror($errorcode); | ||
+ | die("Couldn't write to socket: [$errorcode] $errormsg"); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | if(!$connected) { | ||
+ | die("FastCGI daemon didn't start accepting connections"); | ||
+ | } | ||
+ | |||
+ | return $sock; | ||
+ | } | ||
+ | |||
+ | function pass_request() { | ||
+ | $sock = connect(); | ||
+ | |||
+ | $env = array(); | ||
+ | foreach($_SERVER as $k => $v) { | ||
+ | if(!is_array($v)) { | ||
+ | $env[$k] = $v; | ||
+ | } | ||
+ | } | ||
+ | $env['PATH_INFO'] = @$env['REQUEST_URI']; # for django | ||
+ | |||
+ | # Request IDs are supposed to be kept as small as possible | ||
+ | # while remaining unique :S | ||
+ | #$requestId = (int)(rand()); | ||
+ | $requestId = 1; | ||
+ | |||
+ | # Begin the request | ||
+ | $rec = new Record(FCGI_BEGIN_REQUEST, $requestId); | ||
+ | $rec->contentData = pack(FCGI_BeginRequestBody, FCGI_RESPONDER, 0); | ||
+ | $rec->contentLength = FCGI_BeginRequestBody_LEN; | ||
+ | $rec->write($sock); | ||
+ | |||
+ | _fcgiParams($sock, $requestId, $env); | ||
+ | _fcgiParams($sock, $requestId, array()); | ||
+ | |||
+ | # Transfer wsgi.input to FCGI_STDIN | ||
+ | $content_length = isset($env['CONTENT_LENGTH']) ? (int)$env['CONTENT_LENGTH'] : 0; | ||
+ | $s = ''; | ||
+ | $fp = fopen("php://input", "r"); | ||
+ | while($content_length > 0) { | ||
+ | $chunk_size = min($content_length, 4096); | ||
+ | $s = fread($fp, $chunk_size); | ||
+ | if(!$s) { | ||
+ | break; | ||
+ | } | ||
+ | |||
+ | $content_length -= strlen($s); | ||
+ | $rec = new Record(FCGI_STDIN, $requestId); | ||
+ | $rec->contentData = $s; | ||
+ | $rec->contentLength = strlen($s); | ||
+ | $rec->write($sock); | ||
+ | } | ||
+ | fclose($fp); | ||
+ | |||
+ | # Empty FCGI_DATA stream | ||
+ | $rec = new Record(FCGI_DATA, $requestId); | ||
+ | $rec->write($sock); | ||
+ | |||
+ | # Main loop. Process FCGI_STDOUT, FCGI_STDERR, FCGI_END_REQUEST | ||
+ | # records from the application. | ||
+ | $result = array(); | ||
+ | $err = ''; | ||
+ | while(True) { | ||
+ | $inrec = new Record(); | ||
+ | $inrec->read($sock); | ||
+ | if($inrec->type == FCGI_STDOUT) { | ||
+ | if($inrec->contentData) { | ||
+ | $result[] = $inrec->contentData; | ||
+ | } | ||
+ | else { | ||
+ | # TODO: Should probably be pedantic and no longer | ||
+ | # accept FCGI_STDOUT records?" | ||
+ | } | ||
+ | } | ||
+ | else if($inrec->type == FCGI_STDERR) { | ||
+ | # Simply forward to wsgi.errors | ||
+ | $err .= $inrec->contentData; | ||
+ | #environ['wsgi.errors'].write(inrec.contentData) | ||
+ | } | ||
+ | else if($inrec->type == FCGI_END_REQUEST) { | ||
+ | # TODO: Process appStatus/protocolStatus fields? | ||
+ | break; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | # Done with this transport socket, close it. (FCGI_KEEP_CONN was not | ||
+ | # set in the FCGI_BEGIN_REQUEST record we sent above. So the | ||
+ | # application is expected to do the same.) | ||
+ | socket_close($sock); | ||
+ | |||
+ | $result = implode('', $result); | ||
+ | |||
+ | # Parse response headers from FCGI_STDOUT | ||
+ | $status = '200 OK'; | ||
+ | $headers = array(); | ||
+ | $pos = 0; | ||
+ | while(True) { | ||
+ | $eolpos = strpos($result, "\n", $pos); | ||
+ | if($eolpos < 0) { | ||
+ | break; | ||
+ | } | ||
+ | $line = substr($result, $pos, $eolpos-$pos-1); | ||
+ | $pos = $eolpos + 1; | ||
+ | |||
+ | # strip in case of CR. NB: This will also strip other | ||
+ | # whitespace... | ||
+ | $line = trim($line); | ||
+ | |||
+ | # Empty line signifies end of headers | ||
+ | if(trim($line) == "") { | ||
+ | break; | ||
+ | } | ||
+ | |||
+ | # TODO: Better error handling | ||
+ | $parts = explode(":", $line, 2); | ||
+ | $header = $parts[0]; | ||
+ | $value = $parts[1]; | ||
+ | $header = strtolower(trim($header)); | ||
+ | $value = trim($value); | ||
+ | |||
+ | if($header == 'status') { | ||
+ | # Special handling of Status header | ||
+ | $status = $value; | ||
+ | if(strpos($status, ' ') < 0) { | ||
+ | # Append a dummy reason phrase if one was not provided | ||
+ | $status .= ' FCGIApp'; | ||
+ | } | ||
+ | header("HTTP/1.0 ".$status); | ||
+ | } | ||
+ | else { | ||
+ | $headers[] = array($header, $value); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | $result = substr($result, $pos); | ||
+ | |||
+ | return array($headers, $result); | ||
+ | } | ||
+ | |||
+ | $req = pass_request(); | ||
+ | |||
+ | foreach($req[0] as $header) { | ||
+ | header($header[0] .": ". $header[1], false); | ||
+ | } | ||
+ | |||
+ | print $req[1]; | ||
+ | ?> | ||
+ | </source> | ||
+ | |||
+ | Sumber: https://github.com/shish/spawn-fcgi.php/blob/master/spawn-fcgi.php | ||
+ | |||
+ | ===Tambahkan .htaccess=== | ||
+ | |||
+ | Agar script dapat diakses melalui root URL, silakan tambahkan .htaccess berikut Mini: | ||
+ | <source lang="htaccess"> | ||
+ | RewriteEngine On | ||
+ | RewriteBase / | ||
+ | RewriteCond %{REQUEST_FILENAME} !-f | ||
+ | RewriteRule ^(.*)$ spawn-fcgi.php [L] | ||
+ | </source> | ||
[[Kategori:Setting_CMS]] | [[Kategori:Setting_CMS]] |
Untuk melakukan instalasi perl Dancer, berikut adalah langkah-langkahnya:
Daftar isi |
Silakan anda buka tiket untuk meminta staf kami menginstalkan paket rh-perl524 ke sistem.
Tambahkan baris berikut di `~/.bashrc_local`:
source scl_source enable rh-perl524 export PATH="$PATH:~/perl5/bin" export PERL5LIB=$HOME/perl5/lib/perl5
Aktifkan konfigurasi tersebut dengan `source ~/.bashrc`
Gunakan perintah berikut untuk menginstall Dancer:
$ cpanm --force Dancer2 FCGI FCGI::ProcManager`
Gunakan perintah berikut untuk membuat skeleton aplikasi dancer:
$ dancer2 -a MyApp && cd MyApp`
Untuk menjalankan aplikasi Dancer tersebut, gunakan perintah:
$ plackup s FCGI --listen $HOME/myapp.sock myapp.psgi
Anda juga perlu mengganti permission socket agar dapat diakses oleh webserver:
$ chmod 777 $HOME/myapp.sock
Masuk ke Control Panel, lalu ke menu Language - PHP. Dan edit konfigurasi untuk versi PHP yang digunakan. Tambahkan baris berikut ke konfigurasi tersebut:
extension=sockets.so
Gunakan script ini untuk membuat client FastCGI:
<?php /* * Configure these by adding two define()s to spawn-fcgi.conf.php: * * SPAWN should be a command to spawn a fastcgi process on a socket * SOCKET should point to the socket * * the example SPAWN is a web.py app (see demo.py) */ define("SOCKET", '/home/xxx/myapp.sock'); define("SPAWN", '-'); /* * Spawn-FCGI.php: A script to translate PHP requests into FastCGI * requests, thus allowing hosting of FastCGI apps (good) on any * PHP-compatible web host (cheap, common). * * This is almost a direct port of Flup's FastCGI test harness, * flup_fcgi_client.py (c) 2006 Allan Saddi <allan@saddi.com> + * 2011 Vladimir Rusinov <vladimir@greenmice.info> * * Modified to take request data from the environment rather than * from function parameters. * * PHP port + modifications (c) 2012 Shish <webmaster@shishnet.org> * * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * FastCGI constants */ define('FCGI_LISTENSOCK_FILENO', 0); define('FCGI_HEADER_LEN', 8); define('FCGI_VERSION_1', 1); define('FCGI_BEGIN_REQUEST', 1); define('FCGI_ABORT_REQUEST', 2); define('FCGI_END_REQUEST', 3); define('FCGI_PARAMS', 4); define('FCGI_STDIN', 5); define('FCGI_STDOUT', 6); define('FCGI_STDERR', 7); define('FCGI_DATA', 8); define('FCGI_GET_VALUES', 9); define('FCGI_GET_VALUES_RESULT', 10); define('FCGI_UNKNOWN_TYPE', 11); define('FCGI_MAXTYPE', FCGI_UNKNOWN_TYPE); define('FCGI_NULL_REQUEST_ID', 0); define('FCGI_KEEP_CONN', 1); define('FCGI_RESPONDER', 1); define('FCGI_AUTHORIZER', 2); define('FCGI_FILTER', 3); define('FCGI_REQUEST_COMPLETE', 0); define('FCGI_CANT_MPX_CONN', 1); define('FCGI_OVERLOADED', 2); define('FCGI_UNKNOWN_ROLE', 3); define('FCGI_MAX_CONNS', 'FCGI_MAX_CONNS'); define('FCGI_MAX_REQS', 'FCGI_MAX_REQS'); define('FCGI_MPXS_CONNS', 'FCGI_MPXS_CONNS'); # SHIT: PHP needs different patterns for encode and decode define('FCGI_Header', 'CCnnCx'); define('FCGI_Header2', 'Cversion/Ctype/nrequestId/ncontentLength/CpaddingLength/x'); define('FCGI_BeginRequestBody', 'nCx5'); define('FCGI_EndRequestBody', 'NCx3'); define('FCGI_UnknownTypeBody', 'Cx7'); # SHIT: PHP has no calcsize; so we calculate by hand and hardcode the result define('FCGI_BeginRequestBody_LEN', 8); # calcsize(FCGI_BeginRequestBody)); define('FCGI_EndRequestBody_LEN', 8); # calcsize(FCGI_EndRequestBody)); define('FCGI_UnknownTypeBody_LEN', 8); # calcsize(FCGI_UnknownTypeBody)); /* * Decodes a name/value pair. * * The number of bytes decoded as well as the name/value pair * are returned. */ function decode_pair($s, $pos=0) { $nameLength = ord($s[$pos]); if($nameLength & 128) { $nameLength = unpack('N', substr($s, $pos, 4)); $nameLength = $nameLength[0] & 0x7fffffff; $pos += 4; } else { $pos += 1; } $valueLength = ord($s[$pos]); if($valueLength & 128) { $valueLength = unpack('N', substr($s, $pos, 4)); $valueLength = $valueLength[0] & 0x7fffffff; $pos += 4; } else { $pos += 1; } $name = substr($s, $pos, $nameLength); $pos += $nameLength; $value = substr($s, $pos, $valueLength); $pos += $valueLength; return array($pos, array($name, $value)); } /* * Encodes a name/value pair. * * The encoded string is returned. */ function encode_pair($name, $value) { $nameLength = strlen($name); if($nameLength < 128) { $s = chr($nameLength); } else { $s = pack('N', $nameLength | 0x80000000); } $valueLength = strlen($value); if($valueLength < 128) { $s .= chr($valueLength); } else { $s .= pack('N', $valueLength | 0x80000000); } return $s . $name . $value; } function spawn() { #print "Spawning new FastCGI daemon\n"; $r = shell_exec(SPAWN); } /* * A FastCGI Record. * * Used for encoding/decoding records. */ class Record { function __construct($type=FCGI_UNKNOWN_TYPE, $requestId=FCGI_NULL_REQUEST_ID) { $this->version = FCGI_VERSION_1; $this->type = $type; $this->requestId = $requestId; $this->contentLength = 0; $this->paddingLength = 0; $this->contentData = ''; } /* * Attempts to receive length bytes from a socket, blocking if necessary. * (Socket may be blocking or non-blocking.) */ function _recvall($sock, $length) { $dataList = array(); $recvLen = 0; while($length) { $d = socket_recv($sock, $data, $length, null); if($d === false) { $r = array($sock); $w = array(); $x = array(); socket_select($r, $w, $x, NULL); continue; } if(!$data) { break; } $dataList[] = $data; $dataLen = strlen($data); $recvLen += $dataLen; $length -= $dataLen; } return array(implode('', $dataList), $recvLen); } /* * Read and decode a Record from a socket. */ function read($sock) { try { $parts = $this->_recvall($sock, FCGI_HEADER_LEN); $header = $parts[0]; $length = $parts[1]; } catch(Exception $e) { throw new EOFError(); } if($length < FCGI_HEADER_LEN) { throw new EOFError(); } $parts = unpack(FCGI_Header2, $header); $this->version = $parts['version']; $this->type = $parts['type']; $this->requestId = $parts['requestId']; $this->contentLength = $parts['contentLength']; $this->paddingLength = $parts['paddingLength']; if($this->contentLength) { try { $parts = $this->_recvall($sock, $this->contentLength); $this->contentData = $parts[0]; $length = $parts[1]; } catch(Exception $e) { throw new EOFError(); } if($length < $this->contentLength) { throw new EOFError(); } } if($this->paddingLength) { try { $this->_recvall($sock, $this->paddingLength); } catch(Exception $e) { throw new EOFError(); } } } /* * Writes data to a socket and does not return until all the data is sent. */ function _sendall($sock, $data) { $length = strlen($data); while($length) { $sent = socket_send($sock, $data, strlen($data), 0); if($sent === FALSE) { $errorcode = socket_last_error(); #if($errorcode == 107) { # ENOTCONN # spawn(); # continue; #} #else if($e[0] == errno.EAGAIN) { # #select.select([], [sock], []) # continue; #} #else { $errormsg = socket_strerror($errorcode); die("Couldn't write to socket: [$errorcode] $errormsg"); #} } $data = substr($data, $sent); $length -= $sent; } } /* * Encode and write a Record to a socket. */ function write($sock) { $this->paddingLength = -$this->contentLength & 7; $header = pack(FCGI_Header, $this->version, $this->type, $this->requestId, $this->contentLength, $this->paddingLength); $this->_sendall($sock, $header); if($this->contentLength) { $this->_sendall($sock, $this->contentData); } if($this->paddingLength) { $this->_sendall($sock, str_repeat("\x00", $this->paddingLength)); } } } function _fcgiParams($sock, $requestId, $params) { $rec = new Record(FCGI_PARAMS, $requestId); $data = array(); foreach($params as $name => $value) { $data[] = encode_pair($name, $value); } $data = implode('', $data); $rec->contentData = $data; $rec->contentLength = strlen($data); $rec->write($sock); } function connect() { $sock = socket_create(AF_UNIX, SOCK_STREAM, 0); $connected = false; $errors = 0; while(!$connected && $errors < 5) { $connected = @socket_connect($sock, SOCKET); if($connected === FALSE) { $errorcode = socket_last_error(); # no socket, or first connection refusal if($errorcode == 2 || ($errorcode == 111 && $errors == 0)) { spawn(); } # ECONNREFUSED; we started a process but it isn't running yet else if($errorcode == 111) { sleep(1); $errors++; } else { $errormsg = socket_strerror($errorcode); die("Couldn't write to socket: [$errorcode] $errormsg"); } } } if(!$connected) { die("FastCGI daemon didn't start accepting connections"); } return $sock; } function pass_request() { $sock = connect(); $env = array(); foreach($_SERVER as $k => $v) { if(!is_array($v)) { $env[$k] = $v; } } $env['PATH_INFO'] = @$env['REQUEST_URI']; # for django # Request IDs are supposed to be kept as small as possible # while remaining unique :S #$requestId = (int)(rand()); $requestId = 1; # Begin the request $rec = new Record(FCGI_BEGIN_REQUEST, $requestId); $rec->contentData = pack(FCGI_BeginRequestBody, FCGI_RESPONDER, 0); $rec->contentLength = FCGI_BeginRequestBody_LEN; $rec->write($sock); _fcgiParams($sock, $requestId, $env); _fcgiParams($sock, $requestId, array()); # Transfer wsgi.input to FCGI_STDIN $content_length = isset($env['CONTENT_LENGTH']) ? (int)$env['CONTENT_LENGTH'] : 0; $s = ''; $fp = fopen("php://input", "r"); while($content_length > 0) { $chunk_size = min($content_length, 4096); $s = fread($fp, $chunk_size); if(!$s) { break; } $content_length -= strlen($s); $rec = new Record(FCGI_STDIN, $requestId); $rec->contentData = $s; $rec->contentLength = strlen($s); $rec->write($sock); } fclose($fp); # Empty FCGI_DATA stream $rec = new Record(FCGI_DATA, $requestId); $rec->write($sock); # Main loop. Process FCGI_STDOUT, FCGI_STDERR, FCGI_END_REQUEST # records from the application. $result = array(); $err = ''; while(True) { $inrec = new Record(); $inrec->read($sock); if($inrec->type == FCGI_STDOUT) { if($inrec->contentData) { $result[] = $inrec->contentData; } else { # TODO: Should probably be pedantic and no longer # accept FCGI_STDOUT records?" } } else if($inrec->type == FCGI_STDERR) { # Simply forward to wsgi.errors $err .= $inrec->contentData; #environ['wsgi.errors'].write(inrec.contentData) } else if($inrec->type == FCGI_END_REQUEST) { # TODO: Process appStatus/protocolStatus fields? break; } } # Done with this transport socket, close it. (FCGI_KEEP_CONN was not # set in the FCGI_BEGIN_REQUEST record we sent above. So the # application is expected to do the same.) socket_close($sock); $result = implode('', $result); # Parse response headers from FCGI_STDOUT $status = '200 OK'; $headers = array(); $pos = 0; while(True) { $eolpos = strpos($result, "\n", $pos); if($eolpos < 0) { break; } $line = substr($result, $pos, $eolpos-$pos-1); $pos = $eolpos + 1; # strip in case of CR. NB: This will also strip other # whitespace... $line = trim($line); # Empty line signifies end of headers if(trim($line) == "") { break; } # TODO: Better error handling $parts = explode(":", $line, 2); $header = $parts[0]; $value = $parts[1]; $header = strtolower(trim($header)); $value = trim($value); if($header == 'status') { # Special handling of Status header $status = $value; if(strpos($status, ' ') < 0) { # Append a dummy reason phrase if one was not provided $status .= ' FCGIApp'; } header("HTTP/1.0 ".$status); } else { $headers[] = array($header, $value); } } $result = substr($result, $pos); return array($headers, $result); } $req = pass_request(); foreach($req[0] as $header) { header($header[0] .": ". $header[1], false); } print $req[1]; ?>
Sumber: https://github.com/shish/spawn-fcgi.php/blob/master/spawn-fcgi.php
Agar script dapat diakses melalui root URL, silakan tambahkan .htaccess berikut Mini:
Bahasa tak sah.
Anda harus menentukan suatu bahasa seperti ini: <source lang="html4strict">...</source>
Bahasa-bahasa yang didukung oleh pewarnaan sintaks:
4cs, 6502acme, 6502kickass, 6502tasm, 68000devpac, abap, actionscript, actionscript3, ada, algol68, apache, applescript, apt_sources, arm, asm, asp, asymptote, autoconf, autohotkey, autoit, avisynth, awk, bascomavr, bash, basic4gl, bf, bibtex, blitzbasic, bnf, boo, c, c_loadrunner, c_mac, caddcl, cadlisp, cfdg, cfm, chaiscript, cil, clojure, cmake, cobol, coffeescript, cpp, cpp-qt, csharp, css, cuesheet, d, dcl, dcpu16, dcs, delphi, diff, div, dos, dot, e, ecmascript, eiffel, email, epc, erlang, euphoria, f1, falcon, fo, fortran, freebasic, freeswitch, fsharp, gambas, gdb, genero, genie, gettext, glsl, gml, gnuplot, go, groovy, gwbasic, haskell, haxe, hicest, hq9plus, html4strict, html5, icon, idl, ini, inno, intercal, io, j, java, java5, javascript, jquery, kixtart, klonec, klonecpp, latex, lb, ldif, lisp, llvm, locobasic, logtalk, lolcode, lotusformulas, lotusscript, lscript, lsl2, lua, m68k, magiksf, make, mapbasic, matlab, mirc, mmix, modula2, modula3, mpasm, mxml, mysql, nagios, netrexx, newlisp, nsis, oberon2, objc, objeck, ocaml, ocaml-brief, octave, oobas, oorexx, oracle11, oracle8, oxygene, oz, parasail, parigp, pascal, pcre, per, perl, perl6, pf, php, php-brief, pic16, pike, pixelbender, pli, plsql, postgresql, povray, powerbuilder, powershell, proftpd, progress, prolog, properties, providex, purebasic, pycon, pys60, python, q, qbasic, rails, rebol, reg, rexx, robots, rpmspec, rsplus, ruby, sas, scala, scheme, scilab, sdlbasic, smalltalk, smarty, spark, sparql, sql, stonescript, systemverilog, tcl, teraterm, text, thinbasic, tsql, typoscript, unicon, upc, urbi, uscript, vala, vb, vbnet, vedit, verilog, vhdl, vim, visualfoxpro, visualprolog, whitespace, whois, winbatch, xbasic, xml, xorg_conf, xpp, yaml, z80, zxbasic
RewriteEngine On RewriteBase / RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^(.*)$ spawn-fcgi.php [L]
Sosial
Facebook
Twitter
Google Plus
Temukan kami di Google+