How do I use python as a server-side language? - python

I am trying to use Python instead of PHP (just for educational purposes). I am testing my webpages on XAMPP and I already added python and cgi to configs.
I managed to make a very basic webpage with this code
#!/Python/python
print("Content-Type: text/plain;charset=utf-8")
print()
print("Hello World!")
Though, this is it. I can't find any info on how exactly do I serve webpages with Python 3+. Most of the info is outdated or controversial. Is there an up-to-date guide on how to use Python as a server-side language?

What Nicarus said was a valid sugestion but I also recommend some other things.
First, for your development environment you won't need to use xampp or wamp or such things, python has it's own HTTP server, although not the simplest thing to use, the libraries and frameworks I will explain next use that.
So, most python web developers don't use raw python to use python as their programming language for the web. Most developers use a framework or library of some kind. These frameworks range from being rather heavy and opinionated, like Django, to smaller ones like Flask. Most, if not all, of these frameworks provide some kind of easy and quick way to set up a development HTTP server for testing.
I would recommend looking up Django first since it has the most comprehensive tutorials and guides to get you started. Then, ones you're more comfortable in the Python language you can fairly easily use something else with less hand holding.
With django you can start here

Python can be a great side server language, but not in the way PHP is. It is highly recommended to use a framework, like flask.
In PHP you have different .php files (like index.php) that do a basic routing, but in python (with Flask and also some others frameworks) you must define the URI path within the function.
You can see here an example, from its webpage Flask
from flask import Flask
app = Flask(__name__)
#app.route("/")
def hello():
return "Hello World!"
if __name__ == "__main__":
app.run()
And if you look for a API REST framework, take a look to Falcon

For the purposes you mention, this current setup should work (at least for a while):
Apache Setup
Changes in httpd.conf
Change denied to granted
<Directory />
AllowOverride none
Require all granted
</Directory>
Look for Options +Indexes +FollowSynsLinks........ and add +ExecCGI to that line.
Options +Indexes +FollowSymLinks +Multiviews +ExecCGI
Look for AddHandler cgi-script .cgi and add .py to it
AddHandler cgi-script .cgi .py
Changes in httpd-vhosts.conf
<Directory "{Your directory}"/>
Options +Indexes +Includes +FollowSymLinks +MultiViews +ExecCGI
AllowOverride All
Require all granted
</Directory>
example.py
First line of Python code #!C:\{somepath}\python
You need to find the right path and bar convention ( /, \, //...) for the first and commented line of code. In your example is: #!/Python/python
Run this script.py to find it
import sys
print(sys.executable)
Paste the output next to #! and you should be able to test your test-code.py into your **www\ folder
If happens to be the case that it does not work, try different combinations of python, python.exe with different bar conventions like "/" "//" "\" next to the #! line.
To display an HTML file add print ('Content-type: text/html\n\n') on to your .py code.**
Full code
Note f on html_content = f'''<html>...
#!C:\Program Files (x86)\Python37-32\python
# -*- coding: utf-8 -*-
import cgi
stringvar = 'Hello variable'
intvar = 30
html_content = f'''<html>
<head><title>My first Python CGI app</title></head>
<body>
<p>Hello, 'world'!</p>
<p>This is a stringvar = {stringvar} </p>
<p>This is intvar = {intvar} </p>
</body>
</html>'''
print ('Content-type: text/html\n\n')
print (html_content)
"Most of the info is outdated or controversial"
Totally agree. I hope this works!

Related

invoking a cgi script from within an HTML file (on localhost)

I'm starting out with CGI programming and have a question regarding the security aspect of invoking a CGI script from within an index file. Here's the simple CGI-script.
#!/usr/bin/python
print "Content-type:text/html\r\n\r\n"
print '<html>'
print '<head>'
print '<title>Hello Word - First CGI Program</title>'
print '</head>'
print '<body>'
print '<h2>Hello Word! This is my first CGI program</h2>'
print '</body>'
print '</html>'
And here's what the index file looks like:
HELLO
Note that I've called the cgi script using the full URL - http://localhost/cgi-bin/hello.py
My local Apache web server configuration for CGI is like so:
ScriptAlias /cgi-bin/ "/var/www/cgi-bin/"
<Directory "/var/www/cgi-bin">
AllowOverride None
Options None
Require all granted
</Directory>
This script works as expected at the moment, such that when the "Hello" link is clicked, the output of the CGI script is displayed. I have 2 questions related to this:
Is this method of calling CGI scripts correct, since this will pretty much be a site that has various CGI scripts that run different tasks and in all probability will be invoked via buttons or links?
I do not know if I'm asking this question in the proper manner, but is it possible to not show the destination URL? At the moment, localhost/whoisit/ shows the Hyperlink and clicking on the link called "Hello" shows the following URL in the address bar - localhost/cgi-bin/hello.py.
Thank you in advance.
a) yes, it is the correct method to invoke the CGI script.
b) To, hide the details in the URL, you need to learn about URL rewriting. Google it and you will find many tutorials and websites which will teach you this. There are also websites which generate the code for URL rewriting if you give them your original URL. You can just copy-paste that code in the appropriate file as per your server (e.g. .htaccess for apache server).

Placing code outside of document root problems with Apache and Django

I am having trouble fulfilling the Django recommendation for code placement. I have searched google and beyond trying all types of VirtualHost configurations. However I cannot get the Django site to work with Apache like it does with Django's built in test web server.
I am using Django 1.5.4 and mod_wsgi
The Django documentation states that:
Where should this code live?
If your background is in plain old PHP (with no use of modern frameworks), you’re probably used to putting code under the Web server’s document root (in a place such as /var/www). With Django, you don’t do that. It’s not a good idea to put any of this Python code within your Web server’s document root, because it risks the possibility that people may be able to view your code over the Web. That’s not good for security.
Put your code in some directory outside of the document root, such as /home/mycode.
And in trying to do that I am failing.
Here is an example of my directory structure: I have /home/user/djangoRoot which I want for the document root and /home/user/djangoCode for where I want to put the code. I have followed the tutorial running django-admin.py startproject djangoSite and all the folders and files are created as they should. Database sync works great. I can view the site when I use Django's built in testing web server. But I feel like something is wrong with my apache virtual host because I cannot view the site the same way with apache.
Again, in the spirit of keeping code out of the document root, I want djangoRoot as my root directory and djangoCode for my code directory (with djangoSite/djangoSite directories in it that were created after running the django-admin.py start project djangoSite command).
I have tried
Making the DjangoCode/DjangoSite my root directory, but I can see the file structure inthe browser
Eliminating the DocumentRoot from the VirtualHost as quite a few suggessted.
And I have tried what I gathered from django and the rest
None worked.
So here is my current apache virtualhost
WSGIPythonPath /home/user/djangoCode/djangoSite/djangoSite
<VirtualHost *:80>
ServerAdmin webmaster#localhost
ServerName example.com
ServerAlias www.example.com
DocumentRoot /home/user/djangoRoot
<Directory /home/user/djangoRoot>
Options Indexes FollowSymLinks MultiViews
AllowOverride None
Order allow,deny
allow from all
</Directory>
WSGIScriptAlias /djangoRoot /home/user/djangoCode/djangoSite/djangoSite/wsgi.py
<Directory "/home/user/djangoCode/djangoSite/djangoSite/wsgi.py">
<Files wsgi.py>
Order deny,allow
Allow from all
</Files>
</Directory>
...
</VirtualHost>
This currently only allows me to see document root with no sign of django.
Is my virtual host configured wrong?
Am I taking this "code outside of document root too far"?
I really don't understand why you're finding this so hard, but you're clearly not following me at all. The point of the explanation in the docs is that the place where you code lives in your filesystem is completely independent from the point that Apache serves it at. The latter is given by the first parameter to WSGIScriptAlias. The former is given by the second parameter.
The document root is the default place for Apache to serve files from. But you're not serving files, you're running code to serve dynamic content. So, you proxy to the WSGI app, at the point given by the first parameter to WSGIScriptAlias. That is the root URL of your site. In the example you've given, that means that - assuming your domain name is example.com - your Django app will be accessible under example.com/djangoRoot. If you actually visited that URL in your browser, you'd see whatever page is configured under / in your urls.py. That is almost certainly not what you want. In the vast majority of cases, the first parameter - as shown in the docs - should just be /.
So I'm not sure why you think that goes against the security warning. Here, the document root stays at whatever it is by default - usually /var/www - but the code lives in /home/user/djangoCode/... and is served at /.

Configuring apache2 conf for several python web.py apps

I am working on a small web dashboard -project that has backend implemented with python's web.py framework.
The dashboard has all sorts of widget's on it, one of which also has its backend implemented using web.py. The problem is that only one of the designated application entry points seem to function at a time. Both the dashboard's and the widget's apache configurations are placed in the same file. The original configuration file (that actually worked for a while) in apache2/conf.d/ looks like this:
WSGIPythonPath /var/www/ProjectDASHBOARD/api
WSGIScriptAlias /ProjectDASHBOARD/api /var/www/ProjectDASHBOARD/api/api.py/
AddType text/html .py
<Directory /var/www/ProjectDASHBOARD/api/>
Order deny,allow
Allow from all
</Directory>
# Stuff for graphingwidget
WSGIPythonPath /var/www/ProjectDASHBOARD/widgets/graphingwidget/api
WSGIScriptAlias /ProjectDASHBOARD/widgets/graphingwidget/api /var/www/ProjectDASHBOARD/widgets/graphingwidget/api/api.py/
AddType text/html .py
<Directory /var/www/ProjectDASHBOARD/widgets/graphingwidget/api/>
Order deny,allow
Allow from all
</Directory>
This alone does not work, there is also the next piece of code that is needed in both api.py files, checking their approriate paths and adding them if not found (excerpt from the widget's file):
import web
import json
import sys
path = '/var/www/ProjectDASHBOARD/widgets/graphingwidget/api'
if path not in sys.path:
sys.path.append(path)
A similiar check is done for the dashboard.
All of this indeed worked for a whole week, and then suddenly stopped working when trying to install from scratch, making it all the more confusing as to what is wrong. The error received when trying to access the api from a webpage is HTTP Error 500 Internal server error. Then after a few changes to the apache config file ONE of the api's started working:
WSGIPythonPath /var/www/ProjectDASHBOARD/widgets/graphingwidget/api
WSGIPythonPath /var/www/ProjectDASHBOARD/api
WSGIScriptAlias /ProjectDASHBOARD/api /var/www/ProjectDASHBOARD/api/api.py/
WSGIScriptAlias /ProjectDASHBOARD/widgets/graphingwidget/api /var/www/ProjectDASHBOARD/widgets/graphingwidget/api/api.py/
AddType text/html .py
<Directory /var/www/ProjectDASHBOARD/api/>
Order deny,allow
Allow from all
</Directory>
# Stuff for graphingwidget
AddType text/html .py
<Directory /var/www/ProjectDASHBOARD/widgets/graphingwidget/api/>
Order deny,allow
Allow from all
</Directory>
Basically just moved the paths to the beginning of the file, and switched the order around a little bit, and suddenly one of api's start to work again. Changing the order a little bit then makes the other api work and brakes the other one. I don't remember the correct order for the paths, but the point is that it used to work well, then it stopped working when installed to a fresh identical virtual machine, and only one of the api's work depending on the order of the paths.
Initially the configs were in different files, but it didn't work like that. Had all kinds of errors like "Target WSGI script 'path' cannot be loaded as Python module.", and only started to work when they were moved to the same file.
Im thinking here that somehow one of the paths is overwritten by the other, or that all this time the whole config has been fundamentally wrong and has been working only by sheer luck (for a whole week, without issues...)
Any clues as to what is wrong?
Sorry for the late return, but the case was basically had to carefully RTFM at http://webpy.org/install#apachemodwsgi and make use of .htaccess files.
No idea really why the solution in the original question worked as far as it did.

How to deploy Django application at sub-url?

I need to set up a django development environment that is publicly viewable on the internet (I am doing this for school, and my projects need to be viewable by my professor, this isn't a setup that needs much security). I have a virtual server running Ubuntu 8.04 LTS.
I need to have multiple django applications running in subdirectories of my main site. That is, I need mysite.com to be a static page, mysite.com/wordpress to be my wordpress blog, and mysite.com/django1 mysite.com/django2 etc. to be django projects.
I am using apache, and I will either be using sqlite or mysql.
There seem to be as many different ways to install and configure django as there are websites offering advice, and all of them assume a single project is going to be the root of the website. I'd really appreciate some help, thank you.
You can use
WSGIScriptAlias /django1 /home/keratacon/www/django1/wsgi.py
WSGIScriptAlias /django2 /home/keratacon/www/django2/wsgi.py
in your apache+mod_wsgi config, assuming wsgi.py is the name of your wsgi script.
This blog explains the solution (assuming that mod_wsgi is used, with nginx/uwsgi the solution is similar apparently in nginx/uwsgi this is not necessary).
The first parameter of WSGIScriptAlias - the /sub-url will be stripped from the request url and the rest will go to your django app. If your Django app urls all start with /sub-url (which are stripped by mod_wsgi), then you will not be able to show the views at those urls, unless you "re-insert" the /sub-url to the request path part.
import django.core.handlers.wsgi
_application = django.core.handlers.wsgi.WSGIHandler()
def application(environ, start_response):
#the line below will re-append the sub-url to all urls
environ['PATH_INFO'] = environ['SCRIPT_NAME'] + environ['PATH_INFO']
#this one will make django think that it's the only thing running on the server
environ['SCRIPT_NAME'] = '' # my little addition to make it work
return _application(environ, start_response)
Also in your urls.py all urls must be prefixed with the sub-url of your interest.
Finally, the WSGIScriptAlias must be the same as your sub-url:
#the below line will "take-out" the sub-url and pass the rest
#to your wsgi script
WSGIScriptAlias /sub-url /path/to/wsgi_script
Where file /path/to/wsgi_script must contain the definition of application as shown in the first code snippet.
To make the "sub-url" setup explicit in Django, the equivalent request path patching would have to occur within the Django framework.

How to hide "cgi-bin", ".py", etc from my URLs?

Brand new to web design, using python. Got Apache up and running, test python script working in cgi-bin directory. Get valid results when I type in the URL explicitly: ".../cgi-bin/showenv.py"
But I don't want the URL to look that way. Here at stackoverflow, for example, the URLs that display in my address bar never have the messy details showing the script that was used to run them. They're clean of cgi-bin, .py, etc. extensions. How do I do that?
EDIT: Thanks for responses, every single one helpful, lots to learn. I'm going with URL Rewriting for now; example in the docs looks extremely close to what I actually want to do. But I'm committed to python, so will have to look at WSGI down the road.
The python way of writing web applications is not cgi-bin. It is by using WSGI.
WSGI is a standard interface between web servers and Python web applications or frameworks. The PEP 0333 defines it.
There are no disadvantages in using it instead of CGI. And you'll gain a lot. Beautiful URLs is just one of the neat things you can do easily.
Also, writing a WSGI application means you can deploy on any web server that supports the WSGI interface. Apache does so by using mod_wsgi.
You can configure it in apache like that:
WSGIScriptAlias /myapp /usr/local/www/wsgi-scripts/myapp.py
Then all requests on http://myserver.domain/myapp will go to myapp.py's application callable, including http://myserver.domain/myapp/something/here.
example myapp.py:
def application(environ, start_response):
start_response('200 OK', [('Content-type', 'text/plain')])
return ['Hello World!']
I think you can do this by rewriting URL through Apache configuration. You can see the Apache documentation for rewriting here.
You have to use URL Rewriting.
It is not a noob question, it can be quite tricky :)
http://httpd.apache.org/docs/2.0/misc/rewriteguide.html
Hope you find it helpful
this is an excerpt from a .htaccess that I use to achieve such a thing, this for example redirects all requests that were not to index.php to that file, of course you then have to check the server-variables within the file you redirect to to see, what was requested.
Or you simply make a rewrite rule, where you use a RegExp like ^.*\/cgi-bin\/.*\.py$ to determine when and what to rewrite. Such a RegExp must be crafted very carefully, so that rewriting only takes place when desired.
<IfModule mod_rewrite.c>
RewriteEngine On #activate rewriting
RewriteBase / #url base for rewriting
RewriteCond %{REQUEST_FILENAME} !index.php #requested file is not index.php
RewriteCond %{REQUEST_FILENAME} !^.*\.gif$ #requested file is no .gif
RewriteCond %{REQUEST_FILENAME} !^.*\.jpg$ #requested file is no .jpg
RewriteCond %{REQUEST_FILENAME} !-d #is not a directory
RewriteRule . /index.php [L] #send it all to index.php
</IfModule>
The above Example uses RewriteConditions to determine when to rewrite ( .gif's, .jpeg's and index.php are excluded ).
Hmm, so thats a long text already. Hope it was a bit helpful, but you won't be able to avoid learning the syntax of the Apache RewriteEngine.
You'll find the ScriptAlias directive helpful. Using
ScriptAlias /urlpath /your/cgi-bin/script.py
you can access your script via http://yourserver/urlpath.
You also might want to look into mod_passenger, though the last time I used it, WSGI was kind of a "second-class citizen" within the library—it could detect WSGI scripts if it were used to serve the whole domain, but otherwise there are no directives to get it to run a WSGI app.
Just use some good web framework e.g. django and you can have such URLs
more than URLs you will have a better infrastructure, templates, db orm etc

Categories

Resources