Программа C для расширения и запуска PHP

Как мне сделать программу GCC C в Linux, которая:

  • имеет скрипт программы PHP внутри себя, а не в виде отдельного файла
  • расширяется до /tmp
  • оболочки в командной строке php CLI для запуска PHP-скрипта
  • передает аргументы командной строки программы C как аргументы командной строки программы PHP
  • ошибки красиво выводятся с сообщением, если php CLI невозможен в системе

person Volomike    schedule 07.07.2011    source источник
comment
С каким конкретным шагом у вас возникли проблемы? Мы не собираемся писать программу за вас...   -  person bdonlan    schedule 07.07.2011
comment
Я могу нормально вызвать setenv() и system() из C. Проблема заключается в расширении файлового ресурса за пределы файла C.   -  person Volomike    schedule 07.07.2011


Ответы (2)


Сценарий программы PHP может храниться как глобальная char * использовать функции fopen, fwrite для открытия и записи глобальной переменной. Затем используйте popen для выполнения интерпретатора php (это в значительной степени выполнит любую команду, которую вы ему отправите) и укажите дескриптор файла, из которого вы можете прочитать, чтобы получить вывод. Если вам не нужен вывод для вашей программы (или это не является целью), вы можете использовать набор exec для выполнения команды и передать /tmp/filename в качестве аргумента.

Чтобы получить аргументы из программы C, вы будете использовать *argv[] в int main(int argc, char *argv[]), просто помните, что argv[0] — это имя ВАШЕГО приложения (я всегда об этом забываю).

Функции exec вернут -1 и будет установлено значение errno. Страницы руководства должны отвечать на реализацию каждого из них. но на случай, если вы потеряетесь.

char *script = "here are your script contents";

char *php_application_name = "pear";

int main(int argc, char *argv[]) {
  FILE *fd;
  char *filename = create_random_filename("/tmp/");
  fd = fopen(filename, "rw");

  fwrite(script, sizeof(char), strlen(script), fd);

  fclose(fd);

  /* Assuming application executes like
     pear <script> <arguments>
   */
  char *script_args[argc];
  int i = 1;
  script_args[0] = php_application_name;
  script_args[1] = filename;
  for(i = 1; i < argc; i++) {
    script_args[i+1] = argv[i];
  }

  execvp(php_application_name, script_args);
}
person Suroot    schedule 07.07.2011
comment
Я хотел бы добавить, что я адаптировал это, используя следующую технику для встраивания ресурса данных в программу C: linuxjournal.com/content/ - person Volomike; 07.07.2011
comment
Единственная жалоба на это будет заключаться в том, что вы привязываете себя к архитектуре i386 elf. Включив скрипт как встроенный char *, любая арка, которую вы скомпилируете на нем, должна работать. - person Suroot; 07.07.2011
comment
Хорошая точка зрения. Итак, есть ли в C формат HEREDOC с ‹‹‹ ? Прошло так много времени с тех пор, как я работал с C. Мне нужно взломать мои старые руководства по C и переучиться. (Однако в моем случае мне нужен только Linux, но это будет интересная дискуссия для тех, кто ищет другие платформы.) - person Volomike; 07.07.2011
comment
Нет, вы можете использовать строки \` at the end of the each line to continue a char *`. Помните, добавление \` does NOT indicate continue to a new line in the string itself; you will still need a \n` для обозначения новой строки. - person Suroot; 07.07.2011
comment
Пожалуйста, извините за форматирование вышеизложенного, очевидно, SO не ценит \ 's - person Suroot; 07.07.2011
comment
Скажите, разве у вашего fopen() нет ошибки? Я имею в виду, разве не туда должно идти имя файла var? И есть ли способ добавить .php в конец create_random_filename()? - person Volomike; 07.07.2011

Я хочу поддержать @Suroot, а также эту замечательную статью: http://www.linuxjournal.com/content/embedding-file-executable-aka-hello-world-version-5967

Однако весь процесс выглядит так в командной строке Linux:

... во-первых, вы должны быть в Linux, PHP для командной строки (CLI) должен быть включен, и PHP в командной строке не должен иметь никаких ошибок, когда вы выполняете "php -v" или передаете ему тестовый скрипт, который вы знаете, как правило, будет работать в командной строке.

... во-вторых, вам нужно установить GCC для компиляции программ на C.

... создайте рабочий каталог и перейдите в него.

... создайте файл script.php, содержащий этот тестовый код:

<?php

$s1 = @ $argv[1];
$s2 = @ $argv[2];
$s3 = @ $argv[3];

for($i=0;$i<=10;$i++){
    echo "($s1) ($s2) ($s3)\n";
}

... обратите внимание, это только наш тест. Вы можете поместить туда свой собственный код PHP позже, как только вы докажете, что тест работает.

...обратите внимание, что имя "script.php" имеет решающее значение, иначе main.c не будет работать, когда попадет в строку _binary_script_php_start. Сначала это через меня для цикла, потому что я не сделал мысленной связи с тем, что имя переменной вклеивается в этот процесс.

... создайте файл кода C main.c, содержащий этот код внутри:

#include <stdio.h>
#include <stdlib.h>

extern char _binary_script_php_start;
extern char _binary_script_php_end;

int main(int argc, char *argv[]) {
    // EXTRACT OUR RESOURCE OBJECT INTO /tmp/test.php
    char *p = &_binary_script_php_start;
    FILE *fp = fopen("/tmp/test.php","wb");
    while ( p != &_binary_script_php_end ) {
        fputc(*p++,fp);
    }
    fclose(fp);
    // NOW READ IN OUR STANDARD ARGUMENTS AND LAUNCH OUR COMMAND
    int i = 1;
    char *cmd = "php /tmp/test.php";
    char *s = NULL;
    asprintf(&s, "%s",cmd);
    for(i = 1; i < argc; i++) {
        asprintf(&s, "%s \"%s\"",s,argv[i]);
    }
    system(s);
    free(s);
    unlink("/tmp/test.php"); // comment me out for debugging if you want
}

... обратите внимание, я немного заржавел с C (не использовал его с 1980-х годов), и strcpy() не рекомендуется, потому что это небезопасно. Итак, я прочитал о StackOverflow, что мы должны используйте asprintf() в системах GNU Linux. Очевидно, что asprintf() обрабатывает проблемы с переполнением буфера и malloc? Я очень на это надеюсь — я не хочу ввести вас в заблуждение. Пожалуйста, изучите это!

...а теперь начинается волшебство!

... нам нужно встроить script.php в объектный файл "data.o" с помощью этой команды командной строки (таким образом, начиная с приглашения $):

$ objcopy -I binary -O elf32-i386 -B i386 script.php data.o

... теперь мы создаем нашу команду «runme», где мы связываем «data.o» и «main.c» вместе:

$ gcc main.c data.o -o runme

... это затем сделало для нас скомпилированную программу C под названием «runme». Затем мы можем выполнить его, чтобы протестировать:

$ ./runme "test1" "test2 test3" "test4"

... Вы должны увидеть вывод, подобный следующему:

(test1) (test2 test3) (test4)
(test1) (test2 test3) (test4)
(test1) (test2 test3) (test4)
(test1) (test2 test3) (test4)
(test1) (test2 test3) (test4)
(test1) (test2 test3) (test4)
(test1) (test2 test3) (test4)
(test1) (test2 test3) (test4)
(test1) (test2 test3) (test4)
(test1) (test2 test3) (test4)
(test1) (test2 test3) (test4)

... как вы можете видеть, двойные кавычки на самом деле важны - они говорят C и, следовательно, PHP, что параметры должны быть сгруппированы вместе. Вот почему test3 не появляется в последних скобках. Без двойных кавычек вы увидите совершенно другой результат.

На этом этапе вы видите, как мы можем создать программу на C со встроенным PHP-скриптом внутри, которая работает в Linux. (Mac, Windows — вам, вероятно, потребуется немного изменить этот код.) Программа C расширяет наш PHP-скрипт до /tmp, выполняет его и передает ему параметры, которые мы можем прочитать и использовать. С этого момента вы можете пересмотреть script.php, чтобы он делал то, что вам нужно, и вы можете посмотреть на использование уникального имени файла, чтобы вы не затирали чужой файл /tmp/test.php, на всякий случай.

person Volomike    schedule 07.07.2011
comment
У вас будет утечка памяти, ваш цикл for вызывает вызов asprintf, который каждый раз выделяет новый указатель на s. Но вы никогда не освобождаете предыдущие s. Если вы беспокоились о переполнении буфера; проверьте snprintf() (однако вам нужно знать требования к размеру, вы можете сделать это, просуммировав strlen всех ваших argv). - person Suroot; 08.07.2011
comment
@Suroot - пока я отмечаю это как ответ, хотя у него небольшая утечка памяти, потому что это полный процесс. Тем не менее, я буду с вами в автономном режиме, чтобы устранить утечку памяти, и пересмотрю этот ответ. Мне просто нужно правильно изучить конкатенацию строк C. - person Volomike; 12.07.2011