PHP: Установка PHP-модуля в Windows — Manual

PHP: Установка PHP-модуля в Windows - Manual Хостинг

Что такое расширение?

Если вам приходилось использовать PHP, то вы использовали и расширения. За небольшим исключением каждая доступная для использования функция в языке PHP сгруппирована в то или иное расширение. Основная часть функций (более 400) входит в состав

стандартного расширения

. Исходные коды PHP распространяются с порядка 86 расширениями, имеющими примерно по 30 функций в каждом. Посчитав, получим где-то 2500 функций в сумме. Если этого не достаточно,

предлагает свыше 100 дополнительных расширений, ещё больше можно найти на бескрайних просторах интернета.

«Что же, с учётом всего этого множества функций, живущих в расширениях, тогда остаётся вне расширений?» — спросите вы. «Что расширения расширяют? Что такое ядро PHP?»

Ядро PHP реализовано в виде 2-х отдельных частей. Техническая часть языка представлена в виде Zend Engine (ZE). ZE отвечает за преобразование понятного для человека скрипта в понятные для компьютера токены (tokens), после чего выполняет их.

Кроме того, ZE отвечает за управление памятью, область видимости переменных, обработку вызова функций.Второй частью ядра является то, что непосредственно называется «ядром» (the PHP core). Оно отвечает за взаимодействие со слоем SAPI (Server Application Programming Interface, интерфейс взаимодействия PHP с другим серверным ПО — CLI, CGI, Apache и так далее).

Кроме того, ядро реализует обобщённый слой контроля для проверок safe_mode и open_basedir (данные фичи объявлены depricated с версии 5.3), так же, как и слой потоков, который ассоциирует файловые и сетевые I/O операции с функциями fopen, fread и fwrite.

Hello world

Какая вводная статья по программированию может считаться завершённой без примера ставшей уже обязательной программы Hello World? В данном случае, мы рассмотрим создание расширения, которое добавляет в PHP одну единственную функцию, возвращающую строку со словом «Hello World». На PHP вы возможно реализовали бы это примерно так:

Теперь давайте сделаем из этой функции расширение PHP. Первым делом создадим подкаталог

hello

в каталоге

ext/

дерева каталогов исходников PHP и сделаем

cd

в него. В принципе, этот каталог может располагаться где угодно внутри или снаружи дерева каталогов с исходниками, но вам следует поместить его именно сюда для возможности ссылаться на него из статьи в дальнейшем. Здесь вам нужно создать три файла:

  1. конфигурационный файл (config.m4), используемый утилитой phpize для подготовки расширения к компиляции:
    PHP_ARG_ENABLE(hello, whether to enable Hello World support,
    [ --enable-hello Enable Hello World support])

    if test "$PHP_HELLO" = "yes"; then
    AC_DEFINE(HAVE_HELLO, 1, [Whether you have Hello World])
    PHP_NEW_EXTENSION(hello, hello.c, $ext_shared)
    fi

  2. заголовочный файл (php_hello.h), содержащий указания, используемые PHP для загрузки расширений:
    #ifndef PHP_HELLO_H
    #define PHP_HELLO_H 1

    #define PHP_HELLO_WORLD_VERSION "1.0"
    #define PHP_HELLO_WORLD_EXTNAME "hello"

    PHP_FUNCTION(hello_world);

    extern zend_module_entry hello_module_entry;
    #define phpext_hello_ptr &hello_module_entry

    #endif

  3. файл с исходниками (hello.c), содержащий тело функции hello_world:
    #ifdef HAVE_CONFIG_H
    #include "config.h"
    #endif

    #include "php.h"
    #include "php_hello.h"

    static function_entry hello_functions[] = {
    PHP_FE(hello_world, NULL)
    {NULL, NULL, NULL}
    };

    zend_module_entry hello_module_entry = {
    #if ZEND_MODULE_API_NO >= 20010901
    STANDARD_MODULE_HEADER,
    #endif
    PHP_HELLO_WORLD_EXTNAME,
    hello_functions,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    #if ZEND_MODULE_API_NO >= 20010901
    PHP_HELLO_WORLD_VERSION,
    #endif
    STANDARD_MODULE_PROPERTIES
    };

    #ifdef COMPILE_DL_HELLO
    ZEND_GET_MODULE(hello)
    #endif

    PHP_FUNCTION(hello_world)
    {
    RETURN_STRING("Hello World", 1);
    }

Большая часть кода, которую вы видите в предыдущем примере, всего лишь своего рода «клей» — протокол для регистрации расширения в PHP и установления диалога между ними. Реальным же кодом являются только последние 4 строки в файле

hello.c

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

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

большим ай-ай-ай

. Такое действие называется «двойное освобождение» и является частой причиной ошибок сегментации, так как заставляет программу попытаться получить доступ к блоку памяти, который ей больше не принадлежит.


Проще говоря, что бы ZE не начал повторно освобождать память, занимаемую статической строкой (какой является «Hello World» в нашем примере), функция hello_world должна каждый раз при вызове возвращать копию строки.

В принципе функция

RETURN_STRING

может взять на себя ответственность за то, что любая строка, переданная в неё должна быть скопирована, так что бы была возможность безопасно освободить занимаемую ей память позже. Однако, так как выделение памяти под строку, копирование строки и возвращение копии как результата не является стандартным поведением для внутренних функций ZE,

RETURN_STRING

позволяет указать, необходимо ли делать копию переменной или нет с помощью второго аргумента. Для более наглядного описания данной концепции, обратите внимание на следующий фрагмент кода, который функционально идентичен предыдущему:

PHP_FUNCTION(hello_world)
{
char *str;

  str = estrdup("Hello World");
RETURN_STRING(str, 0);
}


В этом примере вы вручную выделили непостоянную память для строки «Hello World», которую передали обратно в вызывающий скрипт с помощьюфункции

RETURN_STRING

, указав ей 0 в качестве второго параметра, что заставляет функцию не делать копию строки, так как она может воспользоваться нашей.

Ini-настройки

Zend Engine предоставляет два подхода для работы с INI-данными. Сейчас мы рассмотрим наиболее простой из них, а к более общему вернёмся после ознакомления с глобальными переменными.

Предположим, вы хотите объявить в файле php.ini настройку hello.greeting для вашего расширения, которая будет содержать значение для вывода функцией hello_world. Для этого нам придётся добавить несколько изменений в файлы hello.c и php_hello.h в рамках изменения структуры hello_module_entry.

PHP_MINIT_FUNCTION(hello);
PHP_MSHUTDOWN_FUNCTION(hello);

PHP_FUNCTION(hello_world);
PHP_FUNCTION(hello_long);
PHP_FUNCTION(hello_double);
PHP_FUNCTION(hello_bool);
PHP_FUNCTION(hello_null);


Далее откройте файл

hello.c

и замените текущую версию

hello_module_entry

на следующую:

zend_module_entry hello_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
STANDARD_MODULE_HEADER,
#endif
PHP_HELLO_WORLD_EXTNAME,
hello_functions,
PHP_MINIT(hello),
PHP_MSHUTDOWN(hello),
NULL,
NULL,
NULL,
#if ZEND_MODULE_API_NO >= 20010901
PHP_HELLO_WORLD_VERSION,
#endif
STANDARD_MODULE_PROPERTIES
};

PHP_INI_BEGIN()
PHP_INI_ENTRY("hello.greeting", "Hello World", PHP_INI_ALL, NULL)
PHP_INI_END()

PHP_MINIT_FUNCTION(hello)
{
REGISTER_INI_ENTRIES();

  return SUCCESS;
}

PHP_MSHUTDOWN_FUNCTION(hello)
{
UNREGISTER_INI_ENTRIES();

  return SUCCESS;
}

Теперь вам следует добавить соответствующую директиву

#include

в начале файла

hello.c

для получения заголовков для работы с INI-файлами:

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "php.h"
#include "php_ini.h"
#include "php_hello.h"


Последнее, что вам осталось – это модифицировать функцию

hello_world

так, что бы она использовала INI-настройку:

PHP_FUNCTION(hello_world)
{
RETURN_STRING(INI_STR("hello.greeting"), 1);
}

Обратите внимание, что вы создаёте копию значения, полученного от

INI_STR

. Причина в том, что строка, возвращаемая

INI_STR

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

Первый набор внесённых в этой главе изменений добавляет два новых метода, с которыми вы должны быть уже знакомы: MINIT и MSHUTDOWN. Как упоминалось ранее, эти методы вызываются при первом запуске SAPI-слоя и в процессе завершения его работы соответственно.

В вашей функции hello_world вы используете макрос INI_STR для получения текущего значения записи hello.greating в качестве строки. Существует совокупность других функций для получения целочисленных значений, значений с плавающей точкой, булевых значений перечисленных ниже.

В дополнение эти функции имеют дубликаты с суффиксом ORIG, позволяющие получить значение записи в том виде, в котором оно записано в файле php.ini (до того, как могло быть изменено посредствам файла .htaccess или функции ini_set).


Перейдём к функции

PHP_INI_ENTRY

. Первым параметром ей передаётся строка, содержащая имя интересующей вас записи в файле

php.ini

. Для того, что бы избежать коллизий между именами записей в

php.ini

, вам следует использовать те же соглашения, что при наименовании функций: имя должно начинаться с префикса, совпадающего с именем расширения. Так же соглашение предусматривает, что разделителем имени расширения от оригинального имени настройки в INI-файлах должна служить точка. В данном случае имя настройки будет выглядеть как

hello.greeting

Вторым параметром является начальное значение настройки, которое всегда задаётся как char* вне зависимости от того, является ли значение числом или нет. Это является следствием того факта, что все настройки в INI-файлах по своей сути текстовые, так как сам файл текстовый. Только последующее использование в скрипте макросов

INI_INTINI_FLT

или

INI_BOOL

вызывает преобразование их типов.


Третьим параметром является модификатор уровня доступа. Это битовая маска, которая определяет когда и как данная INI-настройка может быть модифицирована. Для некоторых настроек, таких как

register_globals

, просто-напросто не имеет смысла позволять изменение значения внутри скрипта с помощью функции

ini_set

, так как данная настройка имеет смысл только во время подготовки обработки запроса – до того как скрипту дана возможность отработать. Другие, такие как

allow_url_fopen

, являются административными настройками, которые пользователи не должны иметь права изменять ни через

ini_set

, ни через директивы

.htaccess

. По-умолчанию значением для этого параметра является значение

PHP_INI_ALL

, указывающее, что значение настройки может меняться где угодно. Также возможны значения

PHP_INI_SYSTEM|PHP_INI_PERDIR

, указывающие, что значение настройки может быть изменено через php.ini или директиву в файле .htaccess, но через функцию ini_set(). Или же возможно значение

PHP_INI_SYSTEM

, означающее, что настройку можно изменить только через файл

php.ini

и нигде больше.

Последний четвёртый параметр позволяет указать функцию обратного вызова (callback), вызываемую при изменении настройки с помощью функции ini_set. Это позволяет расширениям производить более полный контроль над условиями изменения настройки или вызывать соответствующую функцию в зависимости от нового значения настройки.

Ini-настройки и глобальные переменные

Как вы уже знаете, настройки в файле php.ini, объявляемые с помощью функции

PHP_INI_ENTRY

считываются как строки и при необходимости конвертируются в другие форматы с помощью функций

INI_INTINI_FLTINI_BOOL

. Однако, некоторые настройки во время выполнения скрипта могут запрашиваться слишком часто, что приведёт к большому количеству ненужных операций чтения из файла. К счастью, существует возможность инструктировать ZE хранить INI-настройки в особенном типе данных и производить приведение типов только при изменении значения настройки.

MODULE_GLOBALS

в файле p

hp_hello.h

следующим образом:

ZEND_BEGIN_MODULE_GLOBALS(hello)
long counter;
zend_bool direction;
ZEND_END_MODULE_GLOBALS(hello)


Следующим шагом объявите INI-настройку, изменив блок

PHP_INI_BEGINPHP_INI_BEGIN()
PHP_INI_ENTRY("hello.greeting", "Hello World", PHP_INI_ALL, NULL)
STD_PHP_INI_ENTRY("hello.direction", "1", PHP_INI_ALL, OnUpdateBool, direction, zend_hello_globals, hello_globals)
PHP_INI_END()

Теперь инициализируйте настройку в функции

init_globalsstaticvoid php_hello_init_globals(zend_hello_globals *hello_globals)
{
hello_globals->direction = 1;
}

И, наконец, используйте значение INI-настройки в функции

hello_long

для выбора операции над счётчиком:

PHP_FUNCTION(hello_long)
{
if (HELLO_G(direction)) {
HELLO_G(counter) ;
} else {
HELLO_G(counter)--;
}

  RETURN_LONG(HELLO_G(counter));
}


Вот и всё! С помощью метода

OnUpdateBool

(метод является часть ZE), переданного в качестве третьего параметра макроса

STD_PHP_INI_ENTRY

, будет производиться автоматическое приведение типа значения настройки, полученного из файла

php.ini.htaccess

, или с помощью функции

ini_set

, к соответствующему значению TRUE/FALSE, которое вы можете получить прямо внутри скрипта. Последние три параметра функции

STD_PHP_INI_ENTRY

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

Php-инъекция

Ещё хотел рассказать о первой ошибки всех, кто делает единую точку входа для сайта в одном index.php и называет это MVC-фреймворком:

Смотришь на код, и так и хочется чего-нить вредоносного туда передать:

Вторая «стоящая» мысль, это проверка на нахождение файла в текущей директории:

Третья, но не последняя модификация проверки, это использование директивы open_basedir, с её помощью можно указать директорию, где именно PHP будет искать файлы для подключения:

Будьте внимательны, данная директива влияет не только на подключение файлов, но и на всю работу с файловой системой, т.е. включая данное ограничение вы должны быть уверены, что ничего не забыли вне указанной директории, ни кешированные данные, ни какие-либо пользовательские файлы (хотя функции is_uploaded_file() и move_uploaded_file() продолжат работать с временной папкой для загруженных файлов).

Какие ещё возможны проверки? Уйма вариантов, всё зависит от архитектуры вашего приложения.

Хотел ещё вспомнить о существовании «чудесной» директивы allow_url_include (у неё зависимость от allow_url_fopen), она позволяет подключать и выполнять удаленный PHP файлы, что куда как опасней для вашего сервера:

Увидели, запомнили, и никогда не пользуйтесь, благо по умолчанию выключено. Данная возможность вам потребуется чуть реже, чем никогда, во всех остальных случаях закладывайте правильную архитектуру приложения, где различные части приложения общаются посредством API.

Автоматическое подключение

Конструкции с подключением файлов выглядят очень громоздко, так и ещё и следить за их обновлением — ещё тот подарочек, зацените кусочек кода из примера статьи про исключения:

Первой попыткой избежать подобного «счастья» было появление функции __autoload. Сказать точнее, это была даже не определенная функция, эту функцию вы должны были определить сами, и уже с её помощью нужно было подключать необходимые нам файлы по имени класса.

Единственным правилом считалось, что для каждого класса должен быть создан отдельный файл по имени класса (т.е. myClass должен быть внутри файла myClass.php). Вот пример реализации такой функции __autoload() (взят из комментариев к официальному руководству):

Класс который будем подключать:

Файл, который подключает данный класс:

Теперь о проблемах с данной функцией — представьте ситуацию, что вы подключаете сторонний код, а там уже кто-то прописал функцию __autoload() для своего кода, и вуаля:

Ну более-менее картина прояснилась, хотя погодите, все зарегистрированные загрузчики становятся в очередь, по мере их регистрации, соответственно, если кто-то нахимичил в своё загрузчике, то вместо ожидаемого результата может получится очень неприятный баг.

Чтобы такого не было, взрослые умные дядьки описали стандарт, который позволяет подключать сторонние библиотеки без проблем, главное чтобы организация классов в них соответствовала стандарту PSR-0 (устарел уже лет 10 как) или PSR-4. В чём суть требований описанных в стандартах:

Полное имя классаПространство имёнБазовая директорияПолный путь
AcmeLogWriterFile_WriterAcmeLogWriter./acme-log-writer/lib/./acme-log-writer/lib/File_Writer.php
AuraWebResponseStatusAuraWeb/path/to/aura-web/src//path/to/aura-web/src/Response/Status.php
SymfonyCoreRequestSymfonyCore./vendor/Symfony/Core/./vendor/Symfony/Core/Request.php
ZendAclZend/usr/includes/Zend//usr/includes/Zend/Acl.php

Различия этих двух стандартов, лишь в том, что PSR-0 поддерживает старый код без пространства имён (т.е. до версии 5.3.0), а PSR-4 избавлен от этого анахронизма, да ещё и позволяет избежать ненужной вложенности папок.

Благодаря этим стандартам, стало возможно появление такого инструмента как composer — универсального менеджера пакетов для PHP. Если кто пропустил, то есть хороший доклад от pronskiy про данный инструмент.

Выделение памяти

Для того, что бы избежать утечек памяти в плохо написанных расширениях, ZE использует свой собственный внутренний механизм управления памятью, основанный на дополнительном флаге для определения времени жизни данных. Постоянное (

persistent

) выделение памяти означает, что память будет выделена более, чем на время обработки запроса одной страницы. Непостоянное (

non-persistent

) выделение памяти означает освобождение памяти после обработки запроса вне зависимости от того, была ли вызвана функция освобождения памяти. К примеру, выделение памяти под пользовательские переменные носит непостоянный характер, так как по завершению обработки запроса они становятся бесполезными.

Несмотря на то, что расширение в теории может возложить на ZE освобождение непостоянной памяти автоматически по завершению каждого запроса, делать это не рекомендуется. Выделенная память будет оставаться долгое время невостребованной, ассоциированные с этой памятью ресурсы будут иметь меньше шансов быть закрытыми правильно, и, в конце концов, создание путаницы с освобождением памяти — плохая практика. Как вы увидите позже, убедиться, что все данные отчищены верно, достаточно легко.

Давайте кратко сравним традиционные функции выделения памяти (которые стоит использовать только при работе с внешними библиотеками) с функциями постоянного и непостоянного выделения памяти в PHP/ZE.

ТрадиционныеНепостоянныеПостоянные
malloc(count)emalloc(count)pemalloc(count, 1)*
calloc(count, num)ecalloc(count, 1)pecalloc(count, num, 1)
strdup(str)estrdup(str)pestrdup(str, 1)
strndup(str, len)estrndup(str, len)pemalloc() & memcpy()
free(ptr)efree(ptr)pefree(ptr, 1)
realloc(ptr, newsize)erealloc(ptr, newsize)perealloc(ptr, newsize, 1)
malloc(count * num extr)**safe_emalloc(count, num, extr)safe_pemalloc(count, num, extr)

* Семейство функций pemalloc принимает в качестве параметра флаг «постоянности», который позволяет им вести себя как их непостоянные аналоги.
К примеру: emalloc(1234) тоже самое, что и pemalloc(1234, 0)
** safe_emalloc() и (в PHP 5) safe_pemalloc реализуют дополнительную проверку целочисленных переполнений.

Глобальные переменные

Довольно часто расширению требуется обработать переменную в отдельном запросе, сохраняя её значение независимым от других запросов, которые могут обрабатываться в тоже самое время. В немногопоточном SAPI это можно сделать очень просто: всего лишь объявите глобальную переменную в файле с исходным кодом и обращайтесь к ней, когда вам нужно.

Проблема в том, что, так как PHP спроектирован для работы с многопоточными web-серверами (такими как Apache 2 и ISS), ему необходимо хранить глобальные переменные, используемые одним потоком, отдельно от глобальных переменных другого. PHP значительно упрощает эту задачу благодаря использованию слоя абстракции

TSRM

(Thread Safe Resource Manager) иногда называемого

ZTS

(Zend Thread Safety). Фактически в данной статье уже использовались части TSRM, чего вы даже не заметили. (Не пытайтесь найти их, так как пока для вас это слишком сложно).

Первая часть создания потокобезопасной глобальной переменной, как и любой другой глобальной переменной, заключается в её объявлении. В качестве примера мы объявим одну глобальную переменную типа long, начальным значением которой будет 0. Каждый раз, когда функция hello_long будет вызываться, мы будем увеличивать значение глобальной переменной и возвращать её значение.

#ifdef ZTS
#include "TSRM.h"
#endif

ZEND_BEGIN_MODULE_GLOBALS(hello)
long counter;
ZEND_END_MODULE_GLOBALS(hello)

#ifdef ZTS
#define HELLO_G(v) TSRMG(hello_globals_id, zend_hello_globals *, v)
#else
#define HELLO_G(v) (hello_globals.v)
#endif

Вам также предстоит использовать метод

RINIT

, так что необходимо объявить его прототип в заголовке:

PHP_MINIT_FUNCTION(hello);
PHP_MSHUTDOWN_FUNCTION(hello);
PHP_RINIT_FUNCTION(hello);

Теперь давайте перейдём к файлу

hello.c

и добавим следующий код после блока include’ов:

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "php.h"
#include "php_ini.h"
#include "php_hello.h"

ZEND_DECLARE_MODULE_GLOBALS(hello)



Изменим

hello_module_entry

, добавив в него

PHP_RINIT(hello)zend_module_entry hello_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
STANDARD_MODULE_HEADER,
#endif
PHP_HELLO_WORLD_EXTNAME,
hello_functions,
PHP_MINIT(hello),
PHP_MSHUTDOWN(hello),
PHP_RINIT(hello),
NULL,
NULL,
#if ZEND_MODULE_API_NO >= 20010901
PHP_HELLO_WORLD_VERSION,
#endif
STANDARD_MODULE_PROPERTIES
};

И измените вашу функцию MINIT вместе с добавлением ещё нескольких функций для обработки инициализации при старте запроса:

staticvoid php_hello_init_globals(zend_hello_globals *hello_globals)
{
}

PHP_RINIT_FUNCTION(hello)
{
HELLO_G(counter) = 0;

  return SUCCESS;
}

PHP_MINIT_FUNCTION(hello)
{
ZEND_INIT_MODULE_GLOBALS(hello, php_hello_init_globals, NULL);

  REGISTER_INI_ENTRIES();

  return SUCCESS;
}


И, наконец, вы можете изменить функцию

hello_long

, добавив в неё использование глобальной переменной:

PHP_FUNCTION(hello_long)
{
HELLO_G(counter) ;

  RETURN_LONG(HELLO_G(counter));
}

В изменениях, которые вы внесли в файл

php_hello.h

, вы использовали пару макросов –

ZEND_BEGIN_MODULE_GLOBALSZEND_END_MODULE_GLOBALS

. С их помощью была определена структура

zend_hello_globals

, содержащая одну переменную типа long. После этого был определён макрос

HELLO_G

, позволяющий в зависимости от режима компиляции (с учётом или без многопоточности) получать значение из пула потоков или просто взять его из глобальной области видимости.


В файле

hello.c

с помощью макроса

ZEND_DECLARE_MODULE_GLBALS

вы объявили структуру

zend_hello_globals

либо как глобальную (при непотокобезопасной сборке), либо как член пула ресурсов потока. Нам как авторам расширения не нужно задумываться об этом механизме, так как всю работу берёт на себя ZE. И, наконец, вы используете функцию

ZEND_INIT_MODULE_GLOBALS

для выделения идентификатора потокобезопасного ресурса.


Возможно, вы заметили, что функция

php_hello_init_globals

на самом деле ничего не делает. Кроме того, инициализация счётчика значением 0 оказалась в функции

RINIT

. Почему?

Ключ к ответу на этот вопрос кроется в моменте, когда эти функции вызываются. Функция

php_hello_init_globals

вызывается только при запуске нового процесса или потока. Однако, каждый процесс может обслуживать более одного запроса, так что использование этой функции для инициализации нашего счётчика значением 0 будет верно только для первого запроса. Последующий запрос к этому же процессу по прежнему будет работать со старым значением счётчика и, следовательно, не будет начинать отчёт с нуля. Для инициализации счётчика значением 0 для каждого запроса мы использовали функция

RINIT

, которая, как вы уже читали, вызывается перед каждым запросом обработки скрипта. Мы включили функцию

php_hello_init_globals

в наш код как минимум из-за того, что передача NULL в качестве соответствующего параметра

ZEND_INIT_MODULE_GLOBALS

функции

init

приведёт к ошибке сегментации для платформ без поддержки потоков.

Жизненный цикл


Когда происходит запуск заданного SAPI (например, при запуске сервера Apache по команде

/usr/local/apache/bin/apachectl start

), PHP начинает свою работу с запуска подсистемы ядра. К концу процедуры запуска он загружает код каждого расширения и вызывает его функцию

Module Initialization

(MINIT). Это даёт каждому расширению возможность инициализировать внутренние переменные, выделить память под ресурсы, зарегистрировать обработчики ресурсов и свои функции в ZE, что бы при вызове каким-нибудь скриптом функции этого расширения ZE знал, какой код ему выполнять.

Далее PHP ждёт от слоя SAPI запроса на обработку страницы. В случае CGI или CLI SAPI это происходит незамедлительно и только один раз. В случае SAPI Apache, IIS или другого полноценного web-сервера запрос на обработку страницы происходит каждый раз при запросе (возможно конкурентном) страницы удалённым пользователем.

Однако, вне зависимости от того, каким образом пришёл запрос, его обработка начинается с того, что ядро PHP просит ZE настроить окружающую среду для запуска скрипта, после чего вызывает функцию Request Initialization (RINIT) для каждого расширения.

RINIT даёт расширениям возможность настроить специфичные переменные окружения, выделить память для специфичных ресурсов запроса и выполнить другие задания. Наглядным примером функции RINIT в действии может служить расширение session, в котором при включенной настройке session.auto_start функция RINIT автоматически вызывает исполнение функции session_start и инициализирует переменную $_SESSION.

После того, как запрос инициализирован, ZE транслирует PHP скрипт в токены, а затем в опкоды (opcodes), которые он может выполнить. Если какой-нибудь из этих опкодов запрашивает вызов функции из расширения, ZE формирует аргументы для вызова этой функции и временно передаёт ей управление до её завершения.

После того как скрипт завершил своё выполнение, PHP вызывает функцию Request Shutdown (RSHUTDOWN) для каждого расширения, что выполнить все необходимые для завершения чистки (например, сохранение сессионных переменных на диск). Следующим шагом ZE выполняет процесс чистки (также известный как сборка мусора), который фактически выполняет метод unset для каждой переменной, использованной в выполненном скрипте (начиная с PHP 5.3 механизм сборки мусора значительно улучшен).

Завершив обработку запроса, PHP ждёт от SAPI либо запроса на обработку другого скрипта, либо сигнала на завершение. В случае CGI или CLI SAPI «следующий запрос» невозможен, поэтому SAPI инициализирует завершение работы PHP незамедлительно. В процессе завершения PHP перебирает все расширения и для каждого вызывает функцию Module Shutdown (MSHUTDOWN), после чего завершает свою собственную подсистему ядра.

Этот процесс поначалу может показаться немного запутанным, но, погрузившись в работу над расширениями, вы постепенно прочувствуете его.

Использование библиотеки php


Кроме управления зависимостями, Composer также предоставляет
автоподгрузчик классов для этих зависимостей. Убедитесь, что вы
включили этот автозагрузчик в начало своего скрипта или в
код bootstrap() вашего приложения:

После этого можно использовать любой функционал, описанный в
» документации по библиотеке.

Если вы ранее использовали более старый драйвер (т.е. модуль
mongo), то API библиотеки должно быть вам знакомо. Оно содержит
класс » Client
для соединения с MongoDB, класс
» Database
для операций уровня базы данных (т.е. команды, управление коллекциями) и класс
» Collection
для операций уровня коллекции (т.е. методы
» CRUD, управление индексами).


Пример, как вставить документ в коллекцию
beers базы данных demo:

После вставки вы, конечно же, можете запросить только что вставленные данные.
Для этого используйте метод find, который возвращает итерируемый
курсор:

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

Кроме того, классы наследуют
ArrayObject для большего удобства использования.
Более подробно о сериализации и десериализации между переменными PHP и
BSON можно прочитать в спецификации Постоянные данные.

Как настроить расширения (модули) php в cpanel? | php

Чтобы настроить расширения PHP, выполните следующие действия:

1. Войдите в cPanel.

2. В разделе «Программное обеспечение» на главном экране cPanel нажмите «Выбрать версию PHP»:

PHP: Установка PHP-модуля в Windows - Manual

3. Выберите, какие расширения вы хотите включить для текущей версии PHP:

• Чтобы включить расширение, установите флажок рядом с именем расширения.

• Чтобы отключить расширение, снимите флажок рядом с именем расширения.

PHP: Установка PHP-модуля в Windows - Manual

• Нажмите Сохранить, чтобы сохранить настройки расширения.

Чтобы сбросить список расширений до конфигурации по умолчанию, нажмите «Использовать значения по умолчанию».

4. Чтобы изменить настройки для текущей версии PHP:

• Нажмите «Перейти к опциям PHP».

PHP: Установка PHP-модуля в Windows - Manual

• Щелкните значение рядом с настройкой, которую вы хотите изменить.

• В зависимости от типа настройки может появиться список со стандартными настройками, которые вы можете выбрать. Или может появиться текстовое поле, в котором вы сможете ввести значение.

PHP: Установка PHP-модуля в Windows - Manual

• Нажмите «Применить», а затем «Сохранить», чтобы сохранить настройки.

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

5. Новые настройки PHP вступают в силу немедленно.

Как установить composer на хостинг

PHP Composer (пакетный менеджер) — это консольная утилита, которая позволяет быстро скачать все пакеты, зависимости, фрэймворки, используемые выбранным языком программирования.

Много лет для размещения своих сайтов я пользуюсь услугами Reg.ru и сегодня расскажу как установить Composer на виртуальный хостинг этой компании. Крайне редко данное руководство по установке может отличаться, например, если вы используете другой хостинг, в таких случаях советую обратиться за справкой к своему провайдеру.

Первоначальный интерес к Composer у меня возник во время поиска решений для синтаксической подсветки кода, который я публикую в своих статьях. Решение было найдено и успешно используется. Но этим сфера применения не ограничивается, ведь с помощью пакетного менеджера зависимостей решается множество задач.

Также очевидны преимущества использования данного инструмента: разработчику не придётся самостоятельно загружать и подключать необходимые библиотеки и их зависимости, Composer всё сделает за вас! Автозагрузка классов через файл autoload.php подключит в вашем проекте все необходимые пакеты, расположенные в каталоге vendor.

Чтобы установить пакетный менеджер на сервер сперва необходимо подключиться к серверу по SSH-протоколу. Для этого введите в терминале команду:

sshu0963431@31.31.196.176

В этой команде u0963431 — это логин учётной записи хостинга, 31.31.196.176 — это IP-адрес сервера. При корректном подключении каждая следующая строка будет начинаться с -bash-4.1$.

Для удобства дальнейшей установки задайте переменную PHP_PATH. Например, если на сайте используется версия PHP 7.3, то выполните команду следующего вида:

PHP_PATH=/opt/php/7.3/bin/php

На следующих этапах установки вы сможете использовать переменную $PHP_PATH или прописывать полный путь до файла PHP вручную. В дальнейшем этот путь придётся использовать не один раз, поэтому рекомендую задать и использовать переменную.

Создайте каталог bin, в который будет установлен Composer, в корневой папке услуги хостинга следующей командой:

mkdir -p bin

Перейдите в созданный каталог следующей командой:

cd bin

Затем последовательно введите три команды, чтобы скачать Composer в созданный каталог:

curl -sS https:
cd ~
$PHP_PATH bin/composer-setup.php --install-dir=bin --filename=composer

Создайте файл .profile, чтобы запускать нужную версию PHP и установленный Composer из командной строки по команде PHP. Для этого последовательно введите команды:

echo"alias php='$PHP_PATH -c $HOME/php-bin/php.ini'" >> ~/.profile
echo"alias composer='$PHP_PATH -c $HOME/php-bin/php.ini $HOME/bin/composer'" >> ~/.profile

Переменная $HOME — это домашний каталог текущего пользователя на сервере.

Для корректного запуска утилиты по команде Composer при следующем подключении к серверу добавьте строки:

echo'source ~/.profile' >> ~/.bashrc
source ~/.profile

Проверьте правильность установки вводом команды:

composer

При правильной установке терминал ответит:

Пакетный менеджер зависимостей для PHP установлен и готов к работе. На этом я заканчиваю статью, а в следующий раз расскажу как при помощи PHP Composer установить библиотеку Highlight.php, которая предназначена для подсветки синтаксиса на стороне сервера. Оставляйте свои вопросы и комментарии, всем удачи!

Настройка и сборка окружения

Теперь, когда вы ознакомились с теорией работы PHP и Zend Engine, могу поспорить, вам не терпится погрузиться в работу и начать что-нибудь делать. Однако, перед этим вам нужно обзавестись кое-какими утилитами для сборки и настроить окружение для ваших целей.

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

Первый из них это —enable-debug. Эта опция компилирует PHP с дополнительной отладочной информацией в исполняемых файлах, так что при возникновении ошибки сегментации (segfault) вы сможете получить дамп ядра и воспользоваться отладчиком gdb, что бы выяснить, где и почему произошла ошибка.

Название второй опции зависит от того, с какой версией PHP вы собираетесь работать. В PHP 4.3 она называется —enable-experimental-zts, начиная с PHP 5, она переименована в —enable-maintainer-zts. Эта опция заставит PHP думать, что он работает в многопотоковой (multithread) среде, и позволит вам отловить общие ошибки, которые незаметны в среде без потоков, но повлекут нестабильную работу вашего расширения в многопотоковой среде.

Подключаем пакеты с сайта packagist.org

{
    "require": {
        "php":">=5.3.0",
        "silex/silex":"dev-master",
        "twig/twig":">=1.8,<2.0-dev"
    }
}

Здесь я описал зависимость проекта от PHP версии 5.3.0 и выше, от silex (микрофреймворк) и от twig (шаблонизатор). Silex и Twig доступны в виде Composer-пакетов на сайте packagist.org, поэтому дополнительных настроек не требуют. Замечу, что Silex в свою очередь зависит ещё от нескольких пакетов — все они будут скачены и установлены автоматически.

Имя пакета состоит из двух частей разделёных косой чертой: названия поставщика (vendor name) и названия библиотеки. Названием поставщика зачастую является ник автора или имя компании. Иногда, название поставщика совпадает с именем самой библиотеки или фреймворка.

Для каждого пакета обязательно нужно указать номер версии. Это может быть бранч в репозитории, например, «dev-master» — приставка dev сигнализирует, что это имя бранча, а сам бранч соответсвенно называется «master». Для mercurial репозитория аналогичная запись будет выглядеть как «dev-default».

В качестве номера версии можно указать и более сложные правила, используя операторы сравнения. Кстати, если вы скачиваете код из удалённого репозитория, то Composer сканирует теги и имена веток в этом репозитории на предмет чего-то похожего на номера версий, например тег «v1.2.3» будет использован как указатель на версию 1.2.3.

Решение

Композер тянет порой немало данных, поэтому иногда придётся подождать, но в целом не такая уж проблема

Вы имеете в виду IDE-редактор?

Для запуска composer.phar достаточно установить локально php, веб-сервер не нужен

а можно конкретно на примерах? Какое ПО? Я, к примеру, привык делать все сразу на хостинге.

Вон, даже локального веб-сервера не было до этого smile3

Помощь в написании контрольных, курсовых и дипломных работ здесь.

Использование статических библиотекУ меня есть библиотека libcRand.a в которой определен класс cRand. Как мне теперь его использовать.

Использование VB библиотек в C# проектеДобрый день, друзья! Собственно, вопрос в заголовке. Каким образом я могу использовать.

Использование библиотек C# в Delphi

Добрый день. Для работы с карточным принтером пытаюсь использовать библиотеку написанную на C#.

Использование библиотек шифрованияПодскажите пожалуйста!У меня есть документ XML. С помощью какой стандартной библиотеки я могу.

Источник

Сборка расширения


Последним шагом в этом упражнении будет сборка вашего расширения как динамически подгружаемого модуля. Если вы скопировали предыдущие примеры верно, остаётся лишь запустить три команды из каталога ext/hello/:

$ phpize
$ ./configure --enable-hello
$ make

Обратите внимание, что для корректной работы утилиты

phpize

необходимо наличие утилит

m4autoconf

После запуска всех этих команд у вас должен появится файл

hello.so

в папке

ext/hello/modules/

. Теперь, как и любое другое расширение PHP, вы можете просто скопировать его каталог с расширениями (по-умолчанию это

/usr/local/lib/php/extensions/

, но на всякий случай проверьте настройки

php.ini

или воспользуйтесь командой

php-config —extension-dir

) и добавьте строку

extension=hello.sophp.ini

для инициализации загрузки расширения при запуске PHP. Для SAPI типа CGI/CLI это будет следующий запуск скрипта, для SAPI web-серверов типа Apache это будет следующий перезапуск сервера. Давайте попробуем вызвать функцию из командной строки:

Установка php и модулей на ubuntu/debian

PHP

В Debian и Ubuntu есть несколько вариантов работы php: как модуль apache и как php-fpm. Первый вариант удобен тем, кому придется использовать не только сам PHP, но и возможности Apache, такие как .htaccess. Второй же вариат удобен например для Yii или Laravel.

Установка PHP 5 как модуля Apache:

apt-get update
apt-get install libapache2-mod-php5 php5-cli php5-memcache php5-memcached php5-mysql php5-pgsql php5-curl php5-gd php5-imagick php5-intl php5-mcrypt

Установка PHP 7 как модуля Apache:

apt-get update
apt-get install libapache2-mod-php7.0 php7.0-curl php7.0-cli php-memcache php-memcached php7.0-mysql php7.0-pgsql php7.0-gd php7.0-imagick php7.0-intl php7.0-mcrypt

Установка PHP 5 как PHP-FPM:

apt-get update
apt-get install php5-fpm php5-cli php5-memcache php5-memcached php5-mysql php5-pgsql php5-curl php5-gd php5-imagick php5-intl php5-mcrypt

Установка PHP 7 как PHP-FPM

apt-get update
apt-get install php7.0-fpm php7.0-curl php7.0-cli php-memcache php-memcached php7.0-mysql php7.0-pgsql php7.0-gd php7.0-imagick php7.0-intl php7.0-mcrypt

Модули

В Debian и Ubuntu зачастую установка модулей PHP не требует каких-то сложных манипуляций. Для того, чтобы посмотреть, что Вы можете поставить прямо сейчас, нужно сделать:

lynx@lnxdsk:~$ apt-cache search php7.0
php-amqp - AMQP extension for PHP
php-apcu - APC User Cache for PHP
php-all-dev - package depending on all supported PHP development packages
php-gearman - PHP wrapper to libgearman
php-geoip - GeoIP module for PHP
php-gmagick - Provides a wrapper to the GraphicsMagick library
php-gnupg - PHP wrapper around the gpgme library
php-igbinary - igbinary PHP serializer
php-imagick - Provides a wrapper to the ImageMagick library
php-libsodium - PHP wrapper for the Sodium cryptographic library
php-mailparse - Email message manipulation for PHP
php-memcache - memcache extension module for PHP
php-memcached - memcached extension module for PHP, uses libmemcached
php-mongodb - MongoDB driver for PHP
php-msgpack - PHP extension for interfacing with MessagePack
php-oauth - OAuth 1.0 consumer and provider extension
php-http - PECL HTTP module for PHP Extended HTTP Support
php-pinba - Pinba module for PHP
php-propro - propro module for PHP
php-radius - radius client library for PHP
php-raphf - raphf module for PHP
php-redis - PHP extension for interfacing with Redis
php-rrd - PHP bindings to rrd tool system
php-smbclient - PHP wrapper for libsmbclient
php-solr - PHP extension for communicating with Apache Solr server
php-ssh2 - Bindings for the libssh2 library
php-stomp - Streaming Text Oriented Messaging Protocol (STOMP) client module for PHP
php-uploadprogress - file upload progress tracking extension for PHP
php-uuid - PHP UUID extension
php-yac - YAC (Yet Another Cache) for PHP
php-yaml - YAML-1.1 parser and emitter for PHP
php-zmq - ZeroMQ messaging bindings for PHP
php7.0 - server-side, HTML-embedded scripting language (metapackage)
php7.0-bcmath - Bcmath module for PHP
php7.0-bz2 - bzip2 module for PHP
php7.0-cgi - server-side, HTML-embedded scripting language (CGI binary)
php7.0-cli - command-line interpreter for the PHP scripting language
php7.0-common - documentation, examples and common module for PHP
php7.0-curl - CURL module for PHP
php7.0-dba - DBA module for PHP
php7.0-dev - Files for PHP7.0 module development
php7.0-enchant - Enchant module for PHP
php7.0-fpm - server-side, HTML-embedded scripting language (FPM-CGI binary)
php7.0-gd - GD module for PHP
php7.0-gmp - GMP module for PHP
php7.0-imap - IMAP module for PHP
php7.0-interbase - Interbase module for PHP
php7.0-intl - Internationalisation module for PHP
php7.0-json - JSON module for PHP
php7.0-ldap - LDAP module for PHP
php7.0-mbstring - MBSTRING module for PHP
php7.0-mcrypt - libmcrypt module for PHP
php7.0-mysql - MySQL module for PHP
php7.0-odbc - ODBC module for PHP
php7.0-opcache - Zend OpCache module for PHP
php7.0-pgsql - PostgreSQL module for PHP
php7.0-phpdbg - server-side, HTML-embedded scripting language (PHPDBG binary)
php7.0-pspell - pspell module for PHP
php7.0-readline - readline module for PHP
php7.0-recode - recode module for PHP
php7.0-snmp - SNMP module for PHP
php7.0-soap - SOAP module for PHP
php7.0-sqlite3 - SQLite3 module for PHP
php7.0-sybase - Sybase module for PHP
php7.0-tidy - tidy module for PHP
php7.0-xml - DOM, SimpleXML, WDDX, XML, and XSL module for PHP
php7.0-xmlrpc - XMLRPC-EPI module for PHP
php7.0-xsl - XSL module for PHP (dummy)
php7.0-zip - Zip module for PHP

Давайте для примера установим GD для работы с изображениями:

lynx@lnxdsk:~$ sudo apt-get install php7.0-gd
Чтение списков пакетов… Готово
Построение дерева зависимостей
Чтение информации о состоянии… Готово
Заметьте, вместо «php7.0-gd» выбирается «php-gd»
НОВЫЕ пакеты, которые будут установлены:
  php-gd
обновлено 0, установлено 1 новых пакетов, для удаления отмечено 0 пакетов, и 148 пакетов не обновлено.
Необходимо скачать 350 kБ архивов.
После данной операции, объём занятого дискового пространства возрастёт на 1 493 kB.
Пол:1 http://mirror.mephi.ru/debian stretch/main amd64 php-gd amd64 2.5.0-1 [350 kB]
Получено 350 kБ за 0с (2 266 kБ/c)
Выбор ранее не выбранного пакета php-gd.
(Чтение базы данных … на данный момент установлено 61175 файлов и каталогов.)
Подготовка к распаковке …/php-gd_2.5.0-1_amd64.deb …
Распаковывается php-xdebug (2.5.0-1) …
Настраивается пакет php-xdebug (2.5.0-1) …

После установки нам нужно перезапустить apache (эти примеры я показываю от пользователя root):
root@lnxdsk:~# service apache2 restart

Либо php-fpm, смотря, что используете Вы:

root@lnxdsk:~# service php7.0-fpm restart

Чтобы посмотреть список модулей php, который прямо сейчас подключен, можно запустить:

lynx@lnxdsk:~$ php -m
[PHP Modules]
bcmath
bz2
calendar
Core
ctype
curl
date
dba
dom
ereg
exif
fileinfo
filter
ftp
gd
gettext
hash
iconv
intl
json
libxml
mbstring
mhash
mysql
mysqli
openssl
pcntl
pcre
PDO
pdo_mysql
pdo_pgsql
pgsql
Phar
posix
readline
Reflection
session
shmop
SimpleXML
soap
sockets
SPL
standard
sysvmsg
sysvsem
sysvshm
tokenizer
wddx
xdebug
xml
xmlreader
xmlwriter
Zend OPcache
zip
zlib

[Zend Modules]
Xdebug
Zend OPcache

Читайте также:  ✅ VPS против выделенного или облачного хостинга: что лучше в 2022 году?
Оцените статью
Хостинги