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).
Related
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!
Have 2 html files mypage.html and page.html ,want to pass some values from one html to another and in another html how can fetch those values
Code which am using:
with open('page.html', 'w') as myFile:
myFile.write('<html>')
myFile.write('<body>')
myFile.write('<table>')
myFile.write('<tr>')
myFile.write('<td> Interface </td>')
myFile.write('<td> Global </td>')
myFile.write('</tr>')
myFile.write('<tr>')
myFile.write('<td> Interface</td>')
myFile.write('<td> Global</td>')
myFile.write('</% print c /%>')
#myFile.write('<var>params</var>')
myFile.write('</tr>')
myFile.write('</table>')
myFile.write('</body>')
myFile.write('</html>')
#render HTML page
with open('mypage.html', 'w') as myFile:
myFile.write('<html>')
myFile.write('<body>')
myFile.write('<table>')
myFile.write('<tr>')
myFile.write('<td> Host Name </td>')
myFile.write('<td> Result </td>')
myFile.write('</tr>')
myFile.write('<tr>')
c = Cookie.SimpleCookie()
c['mycookie'] = 'cookie_value'
myFile.write('<td> <a href="page.html?params="'+final_dict.keys()[0]+ '>'+final_dict.keys()[0]+'</a></td>')
myFile.write('<td> Fail</td>')
myFile.write('</tr>')
myFile.write('</table>')
myFile.write('</body>')
myFile.write('</html>')
You have a python script which generates html. That is fine.
You are saving that html to a file and then what? Serving the file? I guess you generate the files once and then you have static files. No python code is executed when user actually requests a url. You should change that concept completely.
What you want to happen is:
user types a url in the browser
browser sends request to the server
server executes some python which generates html, but does not save it to a file. It just sends it back to the user
user sees generated html
With that approach, in step 3, python script is executed every time and you have a chance to read the request parameters.
Now, to do that, you need a server.
You could go to the absolute low-level approach, configuring Apache, IIS or whatever to serve .py files by executing python as a CGI script. That would be very similar to what you are currently doing. If you do that, you will learn a lot about how HTTP works, but it is the hard way and not optimal performance-wise
A better option
You can run a python web server which calls python functions to serve each configured url. Take a look at CherryPy and Flask. Flask is very good, but CherryPy may be better suited for beginners.
I suggest you should start with CherryPy. Follow the documentation, look for tutorials...
You can get URL parameters using the built-in array $_GET in php.
To retreive the parameters from the URL, you can insert this PHP code into the html source of the webpage (the one you are opening with the data in the URL):
<?php
echo $_GET['key'] // Will print out the data of the given key
?>
Of course, you can do what you want with this data using PHP. This will only work if you are running the webpage on a web server with PHP enabled.
I have a django web app on A2hosting, where I am using .htaccess files and passenger_wsgi.py. It was working fine the last time I touched it, but then someone who had a look at it later informed me that it was broken.
I created a test situation to find the problem and here's the gist of it.
When I do a GET (to www.geo4ce.com/quiz/test_weird/), it goes to a page with a simple form that just has one input and a submit and an action that has "/quiz/test_weird/" and method="post". When I submit the form, the server expects the "quiz" part of the url to be referring to a path on the file server, can't find it and then logs an error that it can't find it. But, then it checks the test_weird part of the url against my django urls.py file, finds a different view for that and displays it.
A scenario that almost works properly is with www.geo4ce.com/quiz/test_hacked/, that has the same set up, except the form has action = "/anythinghere/quiz/test_hacked/". In this case, the "anythinghere" part of the url gets an error logged, since it doesn't exist on the file server, and then the /quiz/test_hacked/ part of the url works normally to get back to the original web page.
Anyone have any idea how I might be able to fix or debug this?
[EDIT]
I don't think it's the .htaccess file that's the cause. It looks something like this.
PassengerEnabled On
PassengerAppRoot /path/to/app/folder/
# Prevent Apache from serving .htaccess files:
<FilesMatch "^\.htaccess">
Order allow,deny
Deny from all
</FilesMatch>
deny from xxx.yyy.zzz
Apparently the issue is caused by a certain version of Passenger (with RoR). I've been told to switch to using FCGI.
I am studying HTML and CGI. I installed Apache on the ubuntu server, it works fine as I can see the test pages. I put a new webpage that calls a sample Hello world script from /usr/lib/cgi/ bin folder but when I run it I get this error:
Not Found
The requested URL /usr/lib/cgi-bin/save_file.py was not found on this server.
Access rights for the /usr/lib/cgi-bin are all set to root:root and the permissions for the script are a+x.
The HTML file content is as following (taken from one of the samples online):
enctype="multipart/form-data" action="/usr/lib/cgi-bin/save_file.py" method="post"
(I had to remove HTML tags from here as they do not upload correctly but this is the relevant part)
Anybody has any idea why my script - save_file.py is not found?
Use action="/cgi-bin/save_file.py" instead.
In the case of a URL, the root (/) is the root of your webserver, which is set up to be /var/www. It would be quite dangerous for your HTML pages to have access to your root directory, no? Imagine the consequences of allowing action=/bin/rm.
The default configuration of Apache automitically makes /cgi-bin point to /usr/lib/cgi-bin.
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