За последние 24 часа нас посетили 18196 программистов и 1606 роботов. Сейчас ищут 1412 программистов ...

Создаём собственное расширение для php, или трансляция c++ в php

Тема в разделе "Прочее", создана пользователем abrdabr, 25 фев 2017.

  1. abrdabr

    abrdabr Новичок

    С нами с:
    28 янв 2017
    Сообщения:
    774
    Симпатии:
    65
    Доброго инета)) полагаю многие сталкивались с "недоработками" пхп, которые стандартными путями не решались, сейчас мы научимся быдлокодить на c++ с целью повыпендриваться на php)))
    И так нам понадобится
    1) мозг (опционально)
    2) среда разработки визуал студио сообразно версии (в качестве образца возьмём php5.5.10 and vc2012 (не чего личного так разрабы решили) по сцылке https://www.microsoft.com/ru-ru/download/details.aspx?id=30678 ) (рассмотрим вариант с шиндовс тк адаптация с шандовс на линух занимает куда меньше сил)
    3) установленая весия пхп
    ---------------------------------------
    И здесь два пути простой,- скачать шаблон http://dropmefiles.com/OeLQw или попытаться в ручную установить настройки препроцессора.
    путь 1:
    распаковываем архив по адресу винды C:\Users\Пользователь\Documents\Visual Studio 2012\Projects
    где пользователь=никнейм жевательно на латинице так как или сейчас или после вам придётся юзать латиницу в винде а если продолжите юзать винду с кирилицей то вам не избежать таких кошмаров как ср866 или ср1251

    путь 2:
    для компиляции нам понадобятся исходники которые вы должны скачать сообразно вашей версии пыха и опционально поместить в удобном для вас месте по ссылке https://secure.php.net/releases/ выбираем нужную версию и если имеется выбор то source code формат архива не приоритетен, ну может быть вам придётся думать чем его открыть
    из всех этих метробайт мёртвого груза нам понадобятся следующие
    php-версия
    php-версия\main
    php-версия\TSRM
    php-версия\Zend
    а именно запускаем vc2012 переходим проект/свойства win32project1/свойства конфигурации/каталоги включения и добавляем пути к вышеозначенм папкам
    далее нужно перейти по пути
    проект/свойства win32project1/свойства конфигурации/с\с++ /препроцессор/определения препроцессора и добавить следующие строки
    PHP_WIN32 // ваша разрядность
    ZEND_WIN32
    ZEND_DEBUG=0 // редкая опция которую смотрим в phpinfo
    и
    TS
    если у вас сборка TS то ставим строку TS=1 если сборка NTS то не ставим никакой строки

    переходим проект/свойства win32project1/свойства конфигурации/компановщик/дополнительные каталоги билиотек/ добавляем путь "php_Версия/dev"

    ереходим проект/свойства win32project1/свойства конфигурации/компановщик/ввод/дополнительные зависимости и прописываем "php5.lib"

    и я включаю телепатию и видю что у вас нет этого файла))) взять их вы можете из репозитория пыха на гитхабе https://github.com/php/php-src кликнув brranch_master/tags/URversion

    //------------------------------------------------------------
    всё самое лёгкое кончилось)) переходим к проекту, то есть к коду
    для тех кто пошёл по тяжёлому пути создаем проект вин32 консольное приложение для тех кто скачал исходиник открываем проект C:\Users\Пользователь\Documents\Visual Studio 2012\Projects\Win32Project1

    далее удаляем все что нам навязывает vc2012
    далее нам нужно создать три файла (для простоты)
    первый stdafx.h
    Код (Text):
    1. #ifndef STDAFX
    2.  
    3. #define STDAFX
    4. #define PHP_COMPILER_ID "VC11" // здесь идёт дополнительная заглушка различия версий
    5. #include "zend_config.w32.h"// и зенда
    6. #include "php.h"
    7. #include "info.h"
    8. LPCTSTR s = L"test.dll"; // скачок в разработке,- этим мы подключаем дллку не привязаную к зенду, которая описывается в проекте win32project2 для скачавших шаблон
    9. HINSTANCE hlib = LoadLibrary(s); // наследие предыдущей строки
    10. #endif
    конечно имя stdafx и её константы могут быть удалены\заменены\переименованы
    далее мы рассмотрим мое первое расширение пхп для консоли шиндовс
    Код (Text):
    1. #include "stdafx.h"
    2. //----------------------------------------------------------------------------------------------
    3.  
    4.  
    5. PHP_FUNCTION(wcolor){ // объявляем пхп функцию
    6. if(hlib){ //если сторонняя длл подключена
    7. long* in;
    8. long* (*dllHelloWorld) (long* ...);
    9. dllHelloWorld = (long* (*)(long* ...))GetProcAddress(hlib, "wcolor"); // получаем адрес функции находящейся во внешней длл
    10. zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,"l", &in); // получаем параметры перданные пыхом средствами зенда
    11.  
    12. if(dllHelloWorld)  { //если адресс функции получен
    13.     if((int)in>0){
    14. dllHelloWorld(in);
    15.     }else{
    16.     php_error(E_NOTICE,"Value must be more than 0");}
    17.   }else{
    18. php_error(E_WARNING,"Dll function not found");        }
    19. }else{
    20. php_error(E_WARNING,"Dll loading is failed");}
    21.     RETURN_TRUE; }
    22.  
    23. PHP_FUNCTION(wcls){
    24.     //const char *aaa = INI_STR("test.string");
    25. if(hlib){
    26. void (*dllHelloWorld) ();
    27. dllHelloWorld = (void (*)())GetProcAddress(hlib, "wcls");
    28.  
    29. if(dllHelloWorld)  {
    30. dllHelloWorld();
    31.   }else{
    32. php_error(E_WARNING,"Dll function not found");        }
    33. }else{
    34. php_error(E_WARNING,"Dll loading is failed");}
    35.     RETURN_TRUE; }
    36.  
    37. PHP_FUNCTION(wkey){
    38.     int ch;
    39.     //const char *aaa = INI_STR("test.string");
    40. if(hlib){
    41. int (*dllHelloWorld) ();
    42. dllHelloWorld = (int (*)())GetProcAddress(hlib, "wkey");
    43.  
    44. if(dllHelloWorld)  {
    45. ch=dllHelloWorld();
    46.   }else{
    47. php_error(E_WARNING,"Dll function not found");        }
    48. }else{
    49. php_error(E_WARNING,"Dll loading is failed");}
    50. RETURN_LONG ((long)ch); }
    51. //--------------------------------------------------------------------------------------------
    52. #include "end.h"
    --- Добавлено ---
    Здесь мы столкнулись с особенностями зенда,- нельзя подключать внешние библиотеки, нельзя использовать шаблоны и прочие ограничения, выход есть один клепать независимую длл и подключать её. По своей сути движок зенд реализовал свой функционал в полной мере в дефолтных расширениях пхп. В сущности можно реализовать функцию return_string('made by popov');

    Код (Text):
    1. const zend_function_entry test_functions[] = {
    2.     PHP_FE(wcolor, NULL) // идёт перечисление добавляемых функций
    3.     PHP_FE(wcls, NULL)
    4.     PHP_FE(wkey, NULL)
    5.     PHP_FE_END };
    6.  
    7. //-------------------------------------------------------------------------------------------------
    8.  
    9. PHP_INI_BEGIN()
    10. PHP_INI_ENTRY("test.string", "abc", PHP_INI_ALL, NULL) // здесь идёт чтение вхождений в пхп.ини
    11.  
    12. PHP_INI_END()
    13.  
    14.  
    15.  
    16.  
    17. PHP_MINIT_FUNCTION(test) { // функция исполняемая однажды при инициализации расширения
    18.   REGISTER_INI_ENTRIES();
    19.   return SUCCESS; }
    20.  
    21. PHP_MSHUTDOWN_FUNCTION(test) {// тоже при деинициализации
    22.      if(!FreeLibrary(hlib)){php_error(E_WARNING,"Dll free is fail");}
    23.   UNREGISTER_INI_ENTRIES();
    24.   return SUCCESS;}
    25.  
    26. PHP_MINFO_FUNCTION(test) { // устанавливаем значения в пхп.ини на случай если они там не прописаны
    27. php_info_print_table_start();
    28. php_info_print_table_header(2, "First column", "Second column");
    29. php_info_print_table_row(2, "Entry in first row", "Another entry");
    30. php_info_print_table_row(2, "Just to fill", "another row here");
    31. php_info_print_table_end();
    32. DISPLAY_INI_ENTRIES();
    33. }
    34.  
    35.  
    36. zend_module_entry test_module_entry = {
    37.     STANDARD_MODULE_HEADER,       // #if ZEND_MODULE_API_NO >= 20010901
    38.     "test",                       // название модуля
    39.     test_functions,               // указываем экспортируемые функции
    40.     NULL,              // PHP_MINIT(test) если требуются действия при инициализации
    41.     PHP_MSHUTDOWN(test),          // тоже для деинициализации
    42.     NULL,                         // PHP_RINIT(test), Request Initialization
    43.     NULL,                         // PHP_RSHUTDOWN(test), Request Shutdown
    44.     PHP_MINFO(test),              // PHP_MINFO(test), Module Info (для phpinfo())
    45.     "0.1",                        // версия нашего модуля
    46.     STANDARD_MODULE_PROPERTIES };
    47.  
    48. ZEND_GET_MODULE(test)
    далее нужен файл внешней длл с кодом, для которого нужен новый проект (win32project2 в образце)
    Код (Text):
    1. #include <Windows.h>
    2. #include <conio.h>
    3.  
    4. using namespace std;
    5.  
    6. BOOL WINAPI DllMain(HINSTANCE hDll, DWORD dwReason, LPVOID lpReserved)
    7. {
    8.   switch(dwReason)
    9.   {
    10.     case DLL_PROCESS_ATTACH:
    11.       break;
    12.     case DLL_THREAD_ATTACH:
    13.       break;
    14.     case DLL_THREAD_DETACH:
    15.       break;
    16.     case DLL_PROCESS_DETACH:
    17.       break;
    18.   }
    19.   return TRUE;
    20. }
    21.  
    22. extern "C" __declspec(dllexport) void wcolor(long* a){
    23. HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE);
    24. SetConsoleTextAttribute(console, (int)a);
    25. }
    26.  
    27. extern "C" __declspec(dllexport) void wcls(){
    28. system("cls");}
    29.  
    30. extern "C" __declspec(dllexport) int wkey(){ // указываем тип функции а в с++ это равно возвращаемому значению
    31.     if(_kbhit ()){ // и выполняем какие либо действия
    32.     return _getch();
    33.     }else{
    34.         return NULL;}
    35.     }
    --- Добавлено ---
    далее компилируем два проекта, переименовываем второй в test.dll и кидаем test.dll в корень пыха (туда же где лежит php.ini) второй переименовываем по своему усмотрению и кидаем в папку с расширениями /ext
    подключаем расширения в php.ini
    выводим phpinfo(); и радуемся

    +:
    для работы с длл файлами может пригодится программа depends http://dropmefiles.com/y3Ij6 позволяющая работать с длл файлами, в часности выводящая список функций из длл и их адреса

    РНО:
    ошибки (нотайсы) будут постоянно их я побороть не в силах. иногда может помочь указать в проект/компановщик/командная строка/ "/FORCE:MULTIPLE"
    но стоит обратить особое внимание на пути дополнительных библиотек

    так же если что-то не работает нужно сказать "именем великомогущего абрдабр повелеваю тебе ничтожный мелкософт нормально скомилировать расширение" и перечитать мануал это решит 50% проблем

    собственно говоря описание процесса создания расширения оказалось довольно таки трудоёмким занятием, и мне пришлось выкинуть запланированые пояснения и стандартные ошибки, отступления и комментарии, но если ктото столкнётся с чем-то то мб я проявлю экстрасенсорные способности и помогу решить проблему)))
    --- Добавлено ---
    что нужно знать о с++ в своём синтаксисе с++ очень похож на пхп со следующими исключениями:
    1) жесткая типизация. объявляя с++ функцию вы уже должны знать какой тип она вернёт. обходимо при помощи перегрузки...
    2) отсутствие типа string. в с++ все строки это массивы или списки что принесёт не мало проблем при освоении с++
     
    denis01 нравится это.