Understanding Python from a PHP coder's perspective

Chris Angelico rosuav at gmail.com
Mon Dec 7 16:40:22 EST 2015


On Tue, Dec 8, 2015 at 8:07 AM,  <villascape at gmail.com> wrote:
> I am struggling on some general concepts.  My past experience with server-side code is mostly limited to PHP and websites.  I have some file called "whatever.php", the browser accesses it, and PHP parses it and returns HTML, JSON, etc.  Every now and then, I need to run some background PHP script, or have some PHP script initiated by a CRON job, or have some PHP script initiated by the command line running in an endless loop, and while it works, feel other languages might be more appropriate.
>
> So, my interest in Python...
>
> I've read up on Python, and while some aspects seem similar to PHP, some don't.  I have learned how to create Python script, have run it from the command line, and have even accessed it with Apache by placing http://example.com/myscript.py in the browser.  I am used to seeing .php extensions, but never .py extentions, and even visited multiple sites which I knew were written in Python, but never saw the browser expose the .py extensions.  I am obviously missing something.
>
> Why don't I see the .py extension in my browser?
>
> Is Python event driven like PHP, or is it somehow different?
>
> How should I view Python differently than PHP?

Hi there! Welcome to the list, and thank you for trying to understand
the differences, instead of simply expecting Python to behave like the
thing you already know.

To demonstrate what I'm talking about, I'm going to use a tiny
Python-based web site that I knocked together a little while ago. The
source code is on GitHub, and the site itself is public, so you can
see both:

https://github.com/Rosuav/MinstrelHall
http://minstrelhall.com/

The most important file is mh.py - click on that to see the code.

In PHP-based web sites, the structure of your source code exactly
matches the structure of your web site. The file system *is* your web
site; any time the web server (say, Apache) comes across something
that has the .php extension, it goes and runs it as code.

In Python-based web sites like this one, the layout of the source tree
follows a structure that keeps logically-similar things together, and
the structure of the web site is defined by code. As you read through
mh.py, you'll see a number of lines saying @app.route("...") - those
are creating URLs (sloppy terminology, but close enough). There's one
that says @app.route("/"), which handles http://minstrelhall.com/, and
another just underneath it that says @app.route("/campaign/<int:id>"),
which handles http://minstrelhall.com/campaign/6 (and any other
integer ID that might be passed in).

One advantage of this kind of setup is that your URLs don't depend on
your back end. I could replace all this with a Ruby on Rails site, and
nobody would notice the difference. I could put together something
using Node.js to replace the Ruby site, and continue to provide
content at http://minstrelhall.com/campaign/6 - again, nobody would
care.

Another *massive* advantage is a complete separation of code and data.
You can't see it in Minstrel Hall, but here's a web site that has a
static-files collection:

https://github.com/Rosuav/Flask1
http://rosuav.com/1/

(Note that this Flask site isn't running the whole domain, but only
one subdirectory. What Python sees as @app.route("/foo") is actually
http://rosuav.com/1/foo.)

Any files in the static/ directory are made available by the framework
- but they are, by definition, static files. Any file that I put there
will be delivered as-is. Suppose I create a world-writable directory
called "uploads", and then have a script that accepts a form
submission with an attachment, saving the attachment into the uploads
directory. (This, by the way, is not an engineered example; it's a
real-world example from another web site that I host.) If the uploads
directory is inside static, anything saved to there will be viewable
as http://rosuav.com/1/uploads/some_file_name, but - and this is the
important part - no matter what its file extension, *it will not be
run*. You can upload a .py file, and it'll be visible as Python source
code. You can upload a .cgi script, and it'll be visible as plain
text. You can upload a .php file, and nothing will run it.

This is quite tricky to do with PHP, and requires some careful
management of Apache config files (or presumably the equivalent in
nginx or other servers). With Python+Flask (or any other code-based
server setup), it's automatic. This safety makes a *huge* difference
to the compromisability of your web site; you can accept uploads
without worrying about remote users running code and creating reverse
shells and stuff.

So that's a quick potted summary of why the URLs don't reflect the
language used. Python is event-driven, but instead of defining events
at the file level, the way PHP does, they're defined at the function
level. Of course, if you *want* to put ".py" on the end of all your
URLs, Python won't stop you... :)

ChrisA



More information about the Python-list mailing list