22

I have a WordPress install for a personal blog and I'm gradually porting all of the little web bits I have written over the years to pages on the blog.

One such page is http://www.projecttoomanycooks.co.uk/cgi-bin/memory/majorAnalysis.py which is a simple python script that returns a list of words - I'd like to embedd that behavior within a wordpress page - could someone point me in the right direction for the easyist way of running a spot of python within wordpress?

EDIT - following the wonderful answer below, I have got a lot futher... but unfortunately still not quite there...

I have python that executes on server...

projecttoomanycooks server [~/public_html/joereddington/wp-content/plugins]#./hello.py 
Hello World!

and it's in the same directory as the activated plugin...

The python code... which has the following code...

#!/usr/bin/python
print("Hello World!")

The php:

<?php
/**
 * Plugin Name: Joe's python thing.
 * Plugin URI: http://URI_Of_Page_Describing_Plugin_and_Updates
 * Description: A brief description of the Plugin.
 * Version: The Plugin's Version Number, e.g.: 1.0
 * Author: Name Of The Plugin Author
 * Author URI: http://URI_Of_The_Plugin_Author
 * License: A "Slug" license name e.g. GPL2
 */
/*from http://wordpress.stackexchange.com/questions/120259/running-a-python-scri
pt-within-wordpress/120261?noredirect=1#120261  */
add_shortcode( 'python', 'embed_python' );

function embed_python( $attributes )
{
    $data = shortcode_atts(
        array(
            'file' => 'hello.py'
        ),
        $attributes
    );
    $handle = popen( __DIR__ . '/' . $data['file'], 'r');
    $read   = fread($handle, 2096);
    pclose($handle);

    return $read;
}
4
  • 1
    If it's a very simple script, I think I would just rewrite it in PHP as a WordPress plugin/template ;-) But in some cases people use iframes to embed external pages.
    – birgire
    Oct 27, 2013 at 13:29
  • iframe it directly? :]
    – Jesse
    Oct 27, 2013 at 13:36
  • Is this just an accident, or is your python code really mixed with PHP?
    – fuxia
    Nov 5, 2013 at 17:01
  • I pasted the terminal trace, with the files being displayed by the 'more' command... will tidy up a little...
    – Joe
    Nov 5, 2013 at 21:42

3 Answers 3

26

You can use popen() to read or write to a Python script (this works with any other language too). If you need interaction (passing variables) use proc_open().

A simple example to print Hello World! in a WordPress plugin

Create the plugin, register a shortcode:

<?php # -*- coding: utf-8 -*-
/* Plugin Name: Python embedded */

add_shortcode( 'python', 'embed_python' );

function embed_python( $attributes )
{
    $data = shortcode_atts(
        [
            'file' => 'hello.py'
        ],
        $attributes
    );

    $handle = popen( __DIR__ . '/' . $data['file'], 'r' );
    $read = '';

    while ( ! feof( $handle ) )
    {
        $read .= fread( $handle, 2096 );
    }

    pclose( $handle );

    return $read;
}

Now you can use that shortcode in the post editor with [python] or [python file="filename.py"].

Put the Python scripts you want to use into the same directory as the plugin file. You can also put them into a directory and adjust the path in the shortcode handler.

Now create a complex Python script like this:

print("Hello World!")

And that’s all. Use the shortcode, and get this output:

enter image description here

7
  • Correct answer omits that first line of the the python script, at least in my case, needs to be #!/usr/bin/env python
    – MikeiLL
    May 19, 2014 at 23:28
  • 1
    @MikeiLL That depends on the user’s system, so I left it out deliberately.
    – fuxia
    May 20, 2014 at 6:33
  • 1
    basically making a security hole. If you can pipe to python, you can pipe to any other process as well and this can be used to escalate any more trivial exploit. Aug 15, 2018 at 5:13
  • @MarkKaplun yes, this is not a good idea. To do this "right" there will have to be command escaping going in, and JavaScript+PHP escaping going on. This is not a good way to develop anything inside WordPress, unless there is a VERY specific reason to do this. "Your -scientists- programmers were so preoccupied with whether or not they could, they didn’t stop to think if they should." Jan 20, 2020 at 22:15
  • 1
    Hi @MarkKaplun , It might be my lack of understanding of php and wordpress. I do understand that as soon as you can pipe arbitrary commands to python, that then you will be able to exucute aribitrary commands on the host as the user under which the python process runs. But in this example there is only ever a read being done from the pipe, so I do not see how this plugin can be used to actually write to the pipe. Additionally only the people actually being able to modify worpress pages are able to exploit this security hole, so this might be an ok solution for a personal wordpress site. Sep 26, 2020 at 11:21
4

I followed the example script from the first answer, but was getting no output or errors.

I changed this line:

$handle = popen( __DIR__ . '/' . $data['file'], 'r' );

to this:

$handle = popen( __DIR__ . '/' . $data['file'] . ' 2>&1', 'r' );

and then got a "permission denied" message.

On the console, I ran

chmod 777 hello.py

refreshed the page, and everything worked perfectly.

This may be the issue Joe was seeing above. I don't have enough rep to make a comment, sorry. Hope this helps someone.

2
2

Here's a little script that uses proc_open as noted above, to sent one simple text variable to a python script:

add_shortcode( 'execute_python', 'execute_python_with_argv' );

function execute_python_with_argv( $attributes ){

$description = array (     
    0 => array("pipe", "r"),  // stdin
    1 => array("pipe", "w"),  // stdout
    2 => array("pipe", "w")   // stderr
);

$application_system = "python ";
$application_path .= plugin_dir_path( __FILE__ );
$application_name .= "hello.py";
$separator = " ";

$application = $application_system.$application_path.$application_name.$separator;

$argv1 = '"output to receive back from python script"';
$pipes = array();

$proc = proc_open ( $application.$argv1 , $description , $pipes );

//echo proc_get_status($proc)['pid'];

if (is_resource ( $proc ))
{
    echo "Stdout : " . stream_get_contents ( $pipes [1] ); //Reading stdout buffer
    fclose ( $pipes [1] ); //Closing stdout buffer
    fclose ( $pipes [2] ); //Closing stderr buffer

    $return_value = proc_close($proc);
    echo "<br/>command returned: $return_value<br/>";
}

$application_test = glitch_player_DIR.$application_name;

echo "<br/>Is ".$application_test." executable? ".is_executable($application_test)." ";
echo "readable? ".is_readable($application_test)." ";
echo "writable? ".is_writable($application_test)." ";

} //EOF main/shortcode function

Added a few tests as the bottom to see if the python file is rwx. I think a better way to send the argv would be using fwrite, but it wasn't working for me following this tutorial.

Here is the python script I used. As noted in comments above, something like #!/usr/bin/env python may be necessary, depending on server.

#!/usr/bin/env python

from sys import argv

script, what_he_said = argv

print "This is what you submitted: %s \n \n Isn't that amazing, man? " % what_he_said

Not the answer you're looking for? Browse other questions tagged or ask your own question.