Запуск python-скрипта в WordPress
У меня есть установленный WordPress для личного блога, и я постепенно переношу все свои веб-разработки, написанные за эти годы, на страницы блога.
Одна из таких страниц - http://www.projecttoomanycooks.co.uk/cgi-bin/memory/majorAnalysis.py, которая представляет собой простой python-скрипт, возвращающий список слов. Я хотел бы встроить это поведение в страницу WordPress - не могли бы вы подсказать самый простой способ запуска Python в WordPress?
РЕДАКТИРОВАНИЕ - следуя замечательному ответу ниже, я продвинулся намного дальше... но, к сожалению, все еще не совсем достиг цели...
У меня есть Python, который выполняется на сервере...
projecttoomanycooks server [~/public_html/joereddington/wp-content/plugins]#./hello.py
Hello World!
и он находится в том же каталоге, что и активированный плагин...
Python-код... который содержит следующее...
#!/usr/bin/python
print("Hello World!")
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;
}

Вы можете использовать popen()
для чтения или записи в Python-скрипт (это работает и с другими языками). Если вам нужно взаимодействие (передача переменных), используйте proc_open()
.
Простой пример для вывода Hello World! в плагине WordPress
Создайте плагин и зарегистрируйте шорткод:
<?php # -*- coding: utf-8 -*-
/* Plugin Name: Встроенный Python */
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;
}
Теперь вы можете использовать этот шорткод в редакторе записей с помощью [python]
или [python file="filename.py"]
.
Поместите Python-скрипты, которые хотите использовать, в ту же директорию, где находится файл плагина. Вы также можете поместить их в отдельную папку и изменить путь в обработчике шорткода.
Теперь создайте простой Python-скрипт:
print("Hello World!")
И всё готово. Используйте шорткод и получите такой вывод:

Правильный ответ упускает, что первая строка python-скрипта, по крайней мере в моем случае, должна быть #!/usr/bin/env python

@MikeiLL Это зависит от системы пользователя, поэтому я намеренно это опустил.

По сути, это создает уязвимость. Если можно передавать данные в python через пайп, то можно передавать и в любой другой процесс, что может быть использовано для эскалации более тривиальных эксплоитов.

@MarkKaplun да, это не очень хорошая идея. Чтобы сделать это "правильно", потребуется экранирование команд на входе, а также экранирование в JavaScript и PHP. Это не лучший способ разработки внутри WordPress, если только нет ОЧЕНЬ веской причины для этого. "Ваши -учёные- программисты были так увлечены вопросом, смогут ли они это сделать, что не подумали, следует ли им это делать."

Привет @MarkKaplun, возможно, это связано с моим недостаточным пониманием PHP и WordPress. Я понимаю, что как только появляется возможность передавать произвольные команды в Python, то можно выполнять произвольные команды на хосте от имени пользователя, под которым запущен процесс Python. Но в данном примере происходит только чтение из канала, поэтому я не вижу, как этот плагин можно использовать для записи в канал. Кроме того, только те, кто может изменять страницы WordPress, могут эксплуатировать эту уязвимость, поэтому для личного сайта на WordPress такое решение может быть приемлемым.

@M.D., во-первых, необходимо разрешить выполнение команд из PHP, и в зависимости от версии PHP и веб-сервера это может быть возможно только в глобальных настройках, что означает, что любой PHP-скрипт сможет выполнять любые команды в системе. Со стороны Python любой скрипт может выполнять его и использовать любые уязвимости в его безопасности. Возможно, это не так критично, если только вы контролируете сервер и устанавливаете только проверенный код, но даже если люди делают первое, 99.99% сайтов на WordPress не делают второго, поэтому лучше избегать этого, так как никто не может быть уверен, что всегда будет следовать второму правилу.

Правильный способ обмена данными между Python и WordPress — это настроить cron в Python, чтобы он запрашивал у WordPress необходимую информацию. Таким образом, вы обеспечиваете безопасность PHP-части. Также важно убедиться, что запросы отправляет именно Python, но это уже более простая задача. Однако такой асинхронный обмен данными не решает вопрос, который задал автор.

Я следовал примеру скрипта из первого ответа, но не получал никакого вывода или ошибок.
Я изменил эту строку:
$handle = popen( __DIR__ . '/' . $data['file'], 'r' );
на эту:
$handle = popen( __DIR__ . '/' . $data['file'] . ' 2>&1', 'r' );
и затем получил сообщение "permission denied" (отказано в доступе).
В консоли я выполнил команду:
chmod 777 hello.py
обновил страницу, и всё заработало идеально.
Возможно, это была проблема, с которой столкнулся Джо выше. У меня недостаточно репутации, чтобы оставить комментарий, извините. Надеюсь, это поможет кому-то.

Не устанавливайте права 777. Просто сделайте файл исполняемым. chmod +x filename.py
будет достаточно

Установка прав 777 для всего очень опасна. Источник: https://superuser.com/questions/1034079/is-it-safe-to-chmod-777-everything

Вот небольшой скрипт, который использует proc_open
, как упоминалось выше, для передачи одной простой текстовой переменной в Python-скрипт:
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] ); //Чтение буфера stdout
fclose ( $pipes [1] ); //Закрытие буфера stdout
fclose ( $pipes [2] ); //Закрытие буфера stderr
$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 основная/шорткод функция
Добавлено несколько тестов в конце, чтобы проверить, имеет ли Python-файл права rwx
. Я думаю, что лучшим способом передачи argv
было бы использование fwrite, но у меня не получилось следовать этому руководству.
Вот Python-скрипт, который я использовал. Как упоминалось в комментариях выше, что-то вроде #!/usr/bin/env python
может быть необходимо, в зависимости от сервера.
#!/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
