Often the term LAMP appears, LAMP stands for Linux, Apache web server, MySQL database, PHP programming language. For Linux read this book, for apache go to the apache section.
PHP ( Hypertext Preprocessor) is often used as server side programming language. PHP is used to create a dynamic HTML pages or html page content.
Dynamically created pages look as index.php
In the other direction PHP can interpret data being arrived from a user (client, web browser). This happens when forms are sent back to the web server.
When a browser request a page, then the web server sends a header (where the MIME type is defined) following the HTML page.
If the requested page is a page as index.php
, then the server loads this page in
memory, but instead
of sending it out, it is passed to a PHP interpreter. Try out the following index.php
<?php echo "Hello World"; ?>
The PHP interpreter creates what ever is echoed and sends it out.
To not have to create the complete web page, PHP is embedded in HTML containing something as:
<html> <body> <?php echo "Hello World"; ?> </body> </html>
This looks as the well know javascript, but here if the file has the php extension, the code is executed on the server an not on the browser. The browser will therefore not see the PHP code. The browser receives just the result of the PHP code.
If the PHP code arrives at the browser then something went wrong. A simple reason might be that the file has a html extension and the apache server sends it out as it is. An other reason is that the web server does not to support PHP.
For apache make sure php has the apache2 support enabled (gentoo useflag apache2) and load the php module in /etc/conf.d/apache2
APACHE2_OPTS=" <other -D stuff >
-D PHP"
To install php and have apache note about it by
/etc/init.d/apache2 restart. Create a
simple HTML page with the name index.php
and put it under
/var/www/localhost/htdocs/index.php
:
<html> <body> <?php phpinfo(); ?> </body> </html>
Then type http://127.0.0.1/index.php and a full featured php info page should appear. In Gentoo Linux eselect php list apache2 shows the php support
The exec() function allows to run Linux commands in php
<?php $output=null; $retval=null; exec('whoami', $output, $retval); echo "whoami returns status $retval and output:\n"; echo '<pre>'; print_r($output); echo '</pre>'; ?>
One issue is that the programs are run using the user rights of the user that whoami shows. This user as www-data might have missing sudo restrictions for certain commands a wg. Adding it to the sudoers and as root run it as the user www-data using the command runuser -u www-data -- sudo wg Obviously there are some good reasons why restrictions have been configured.
Since php runs on the server debugging is not that easy. xdebug http://xdebug.org/docs/install can be used but uses a specific setup until it runs.
An alternative is showing errors using “display_errors” in the php.ini
file. Under /etc/php more than one php.ini can be found, the directory for apache holds the correct one. If setup as mentioned before the setting can be verified with /var/www/localhost/htdocs/index.php
For security reasons showing displaying errors is off per default.
Finally restart apache.
Or add the following code to php scripts
<?php ini_set("display_errors",1); error_reporting(E_ALL); //code goes here ?>
With CGI (Common Gateway Interface) the web browser (HTTP client) can initiate a communication with a HTTP server and as result some code is running on the server.
This time the data is sent to the HTTP server, the server takes it, does something with it and responds back to the HTTP client the browser.
To keep it simple a basic sample explaining the concept is more helpful than writing pages showing how the data sent to the server, how it is structured, what buttons and forms HTML supports, how the server interprets the data.
Here the example script put on the server:
#!/bin/sh echo Content-type:text/plain echo /bin/date
The script is easily explained, #!/bin/sh tells the server that it has to start it as a regular script. The first echo tells to the server, that it will receive plain text from the CGI executable and finally /bin/date prints date and time in plain text. The server then takes this plain text and send it back to your browser nude as it is. Hopefully the browser understands naked plain ASCII and will show something as:
Sun Aug 17 13:47:11 EDT 2008
An easy test is just typing the following URL into the web browser:
http://127.0.0.1/cgi-bin/getdate.cgi or https://www.linurs.org/cgi-bin/getdate.cgi
This is also a good test if everything works, since many servers have lots of restrictions.
If a symbolic link is used to point to the cgi script, then the web server might to refuse to start the script due to security issue.
The following line can be put in a html page:
<a href="http://www.linurs.org/cgi-bin/getdate.cgi">Show the date</a>
It is nothing else than a Hyperlink, but this time not to a HTML page but to a cgi executable. This gci executable can be everything that runs on the server: A binary, a Perl, python or bash script. If you have the necessary permissions then the server starts this executable after you have clicked on the Hyperlink.
The CGI executable could look as the following bash script:
The server does just a little bit more than just executing the script, it has deviated the stdout, so everything the script prints ends up on the HTTP server application itself. This explains that CGI can make use of all programming languages that can print. Script languages need an interpreter to run, as the bash script needs bash available on the server, for Linux no problem, but for a Windows server a problem.
The above sample could send back other MIME types as text/html, image/gif, image/jpeg, video/mpeg. Sending back HTML, the sample could look as follows:
#!/bin/sh echo Content-type: text/html echo cat <<_End_ <HTML> <HEAD> <TITLE> Date </TITLE> </HEAD> <BODY> <P> The Date is:<B> _End_ /bin/date cat <<_End_ </B> <P> </BODY> </HTML> _End_
Instead of creating some data, that will be send back, you could also pass back a link:
echo Location: /index.html
replaces the echo Content-type line.
A more complex CGI example would show how a form is created on a web page, how all the data inside the form is sent to the http server, how the server gets the data and passes it to the CGI executable, how the CGI executable interprets the data and maybe creates files on the server or interacts with a data base, and finally how it returns more than just nude plain ASCII, since usually the GCI executable returns a HTML page back to the http client (your browser).
Finally you can call a GCI script through the net:
http://www.linurs.org/cgi-bin/getdate.cgi
It is also possible to install a terminal application and use it via cgi. The package cgiterm https://sourceforge.net/projects/cgiterm/can be put under the cgi-bin directory and be started: http://www.linurs.net/cgi-bin/cgiterm/cgiterm.pl
Passing data to the CGI script is done by attaching ?<var1name>
=<value1>
&<var2name>
=<value2>
to the url. Languages as python have a parser to extract the data from the string
#!/usr/bin/python3
import cgi
para=cgi.FieldStorage()
print("Content-Type: text/plain")
print()
print(para.getvalue("<name of the value>
"))
Usually the GET request (an alternative would be using POST) of the HTTP protocol is used to pass the string and therefore the data ends up in the QUERY_STRING variable. Python and most other programming languages allow also to read environmental variables:
#!/usr/bin/python3 import os print("Content-Type: text/plain") print() print(os.getenv('QUERY_STRING'))
So when developing CGI scripts
declare -x QUERY_STRING="<var1name>
=<var1>
&<var2name>
=<var2>
"
sets the environmental variable
Finally the cgi script has environmental variables that can be read.
Services as https://ip-lookup.net/ then tell you where you are.
The above python 2 script could look as simple as
#!/usr/bin/python import cgi print "Content-Type: text/html" print cgi.print_environ() cgi.print_directory() cgi.print_environ_usage()
Or more easy use things as ip2country from http://freenet.mcnabhosting.com/python/ip2country/
Regular CGI are scripts that are getting called and terminated when a web browser calls them. In case of having a python script, this means first the python interpreter must be loaded and then the script can be started and finally everything is unloaded. This can mean a huge overhead for just a couple of script lines.
FastCGI (or FCGI) or FCGI is Simple Common Gateway Interface (SCGI) solves this by loading the CGI script once and uses it for many requests. The script communicates with the web server via a TCP/IP socket (and could therefor be even on an other machine). Both are standardized so SCGI and FCGI can be used on different web server implementations. As a result FGCI and SGCI scripts are no more simple scripts since they need to implement the TCP/IP protocols (they are now similar as daemons running in background and serving requests).
The procedure is that the server has to be setup to start these scripts. The server has to find out what files it can simple send to the browser and what files are really requests for FCGI and are really not files. The above scripts have to interpret such requests and send back to the server.
The socket protocol required to have the fastcgi server taking to lighttpd can be handled by different implementations.
A quite commonly used but badly documented, old and no more maintained implementation is flup and flup is just available for python2 (version 1.0.2). It has sphinx documentation. So change to docs subdirectory and make html
However some people ported flup to python3 but unfortunately this is not very coordinated, (there might be many different 1.0.3 versions around). I found one that after patching worked. I informed the developers about the patch and then the whole thing disappeared from the Internet. Luckily Gentoo kept the source on my PC, so I simply forked it and now also I'm one of the many having his own python3 flup version.
It should be noted that the script below will work for many web server as lighttpd or apache, since it follows the fastgci standard.
A fastcgi script doing this could look like:
#!/usr/bin/env python2 # -*- coding: UTF-8 -*- import sys, os from cgi import escape from flup.server.fcgi import WSGIServer def app(environ, start_response): start_response('200 OK', [('Content-Type', 'text/html')]) yield '<h1>FastCGI Environment</h1>' yield '<table>' for k, v in sorted(environ.items()): yield '<tr><th>{0}</th><td>{1}</td></tr>'.format( escape(k), escape(v)) yield '</table>' WSGIServer(app).run()
A flup.https://pypi.python.org/pypi/flup simple hello world python FCGI script flup would look:
#!/usr/bin/python2.5 def myapp(environ, start_response): start_response('200 OK', [('Content-Type', 'text/plain')]) return ['Hello World!\n'] if __name__ == '__main__': from flup.server.fcgi import WSGIServer WSGIServer(myapp).run()
Environ is a python dictionary that contains all the stuff as the QUERY_STRING that could be extracted via query=environ["QUERY_STRING"]
There is also webpy that allows selecting different objects to be started using its urls variable that contains a regular expression and the matching object to be started.
#!/usr/bin/python import web urls = ( '/(.*)', 'test' ) handler = web.application(urls, globals(), True) class test: def GET(self, name): return "It works!" if __name__ == "__main__": handler.run()
WSGI is the Python Web Server Gateway Interface that serves as middle-ware between a web server and python.
A server that can handle wsgi is uwsgi http://uwsgi-docs.readthedocs.io/en/latest/ unfortunately it is a monster where it is difficult to get an overview.
Scripts could also be started when the web page is loaded.
This is not CGI where the client initiates that code is running by sending data to the server. It is the server that has to know that it has to run code when a page is requested.
With SSI take care that you do not could cause an recursive loop.
To enable SSI (and call a CGI script), just add a special comment:
<!--#include virtual="/cgi-bin/<name of the script>
.cgi"-->
To work the server needs to be configured, to interpret such lines.
AJAX (Asynchronous JavaScript and XML) Allows to exchange data with the web server and modify the web page without re-loading it. The web page contains javascript and sends out a XMLHttpRequest (using GET or POST since it must use the HTTP protocol) to the server and then receives the response behind the scene. Then Javascript is used to modify the web page accordingly. Ajax is a method of combining things to do it and is not something to be installed. However just browsers of the current century support XMLHttpRequest and therefore Ajax.
Old browsers do not support ajax and old Microsoft Internet explorer browser do not support it using HttpReguest. The jQuery Framework helps to deal with different browsers. Alternatively just support new browsers.
What is received can be either text or xml and it can be a file or output from a script. If it is xml then DOM is used to extract the desired information from xml.
On the server a script has to run that echoes back the requested data. cgi can be used or php without any html as:
<?php echo 'hello from ajax'; ?>
The following example reads text output from a cgi script:
<html> <head> <title>Temperature</title> <script type="text/javascript"> function RunMe() { var xmlhttp; xmlhttp=new XMLHttpRequest(); xmlhttp.open("GET","../cgi-bin/temperature.cgi",false); xmlhttp.send(); document.getElementById("myDiv").innerHTML=xmlhttp.responseText; t=setTimeout('RunMe()',1000); } </script> </head> <body onload="RunMe()"> <p>Ajax way to update the text below</p> The temperature is <div id="myDiv"><h2>AJAX</h2></div> </body> </html>
The <div> (or as alternative <span>) is used to get an identifier and not to be worried where inthe html the update has to be occur. The identified id="myDiv" is periodically updated using javascript. xmlhttp.open uses false this means ajax does not run asynchronous but synchronous (Synchronous JavaScript and XML). This means the open command stops until the response has been arrived. This might be ok. But if there are many things to do, waiting is no more an option, so asynchronous is desired.
Asynchronous is done by using a callback function. The request is sent out and then immediately other things can be done. If the response comes back some time later, then the call back function is executed to process the response. Since javascript is an interpreted language, the call back function has to be declared before the open and send methods are called:
<html> <head> <title>Temperature</title> <script type="text/javascript"> function RunMe() { var xmlhttp; xmlhttp=new XMLHttpRequest(); xmlhttp.onreadystatechange=function(){ if (xmlhttp.readyState==4 && xmlhttp.status==200){ document.getElementById("myDiv").innerHTML=xmlhttp.responseText; } } xmlhttp.open("GET","../cgi-bin/temperature.cgi",true); xmlhttp.send(); t=setTimeout('RunMe()',1000); } </script> </head> <body onload="RunMe()"> <p>Ajax way to update the text below</p> The temperature is <div id="myDiv"><h2>AJAX</h2></div> </body> </html>
It seems very simple to have an access counter to count how many times the web page has been accessed. If you are lucky your host provider offers you a solution. If not, then it can get complicated!
An easy way is a shtml using SSI or a php page, that is dynamically built when it is accessed, so just some code to read the actual value from a file, display it, increment it and store the result back to the file is required.
But you probably would like to keep your html extension of your web pages and just add some small thing to it. If you are lucky you can give your files the x permission and use SSI.
If none of those options worked, you can put a static string as the following in your HTML page:
<IMG SRC="cgi-bin/graphical-counter">
It represents a graphical file created by a GCI script. The GCI script has to deliver a MIME type and the graphical file attached.
The graphical file has to be obviously created using the counter value.
Now some instructions (GIF files containing single numbers are attached together to form the counter value):
I originally used the c code found on the Internet, but I modified it to have individual pages supported.
The size constants of the downloaded GIF files needs to match with the settings in the code (int real_height = 13 and int real_width = 9)
After emerge gd it can be compiled gcc -o graphical-counter -lgd graphical-counter.c
Since the access counter supports multiple pages, the page number needs to be defined, this is done with the exported environmental variable:
declare -x QUERY_STRING=page=count
The access counter program can therefore read the exported environmental variable and knows what page counter to be counted.
If you run ./graphical_counter you get some weird response:
Content-type: image/gif GIF87a<????,<v????S?ko?Lo?I??"p.g?ql???Ҫ??????kPI? ?H_??=?q???:I?.64???1(?\&?I9?N??n??,֯x?5?75???6????U?uX?89Y;
This is actually a ASCII header and the binary gif file all in one string.
For further debugging, you would like to split it. So run the program as ./graphical_counter > test.gif then open test.gif with an hex editor (as GHex) that understands pure binary and delete the first bytes until G is the word GIF is the fist character. Then save it and you have your image that you can observe in a picture viewer.
To having running on the server there might be different obstacles especially when the server is not the same computer where you developed the access-counter.
The server probably does not know what versions of the libraries you have used at compilation time and therefore fail. To avoid that recompile the code.
The access counter makes use of the gd library, that is dynamically linked. If the access counter gets copied from the local Gentoo PC having the gd library installed to some Internet server without having the gd library installed, then the access counter fails. If so, you need to statically link the gd library into the access counter (and also the math library).
gcc -o graphical-counter graphical-counter.c /usr/lib/libgd.a /usr/lib/libm.a
or add -static to get rid of the dependencies.
An other way is not using C, and write/use an counter that is written in a language as python that is interpreted on the machine where the server resides. It will run slower but with less hassle.
Move the working directory to your server where it accepts cgi-bin. A first test to see if your script is found and even runs type the following url into your web browser.
You should now see a nice gif number that increments each time you click on the reload button of you browser. If it does not increment then you do not have write access to the file.
Now add a HTML page to your server that calls it
Example 8.1. Access Counter
<HTML> <HEAD> <TITLE>Example of the Graphical Access Counter</TITLE> </HEAD> <BODY> <H1>Graphical Access Counter</H1> This is my Home page. Thank you for visiting. Please come again. <P>This page has been accessed <IMG SRC="/cgi-bin/accesscounter/graphical-counter?page=index"> </IMG> times. </BODY> </HTML>