Модуль переключения версий PHP для ISPmanager

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

    В связи со стремительным выходом новых версий PHP стала задача дать возможность пользователям выбирать для своего аккаунта нужную версию PHP.
    Как обычно есть набор ОС: FreeBSD, Centos. Но модуль при небольших доработках работает на всех ОС и на CL в том числе.

    Для начала поставим нужные версии PHP на сервер и установим все необходимые расширения PHP.

    Для FreeBSD
    Если имеем сервер с установленной давным давно php5.2
    Обновляем порты
    cd /usr/ports/lang/ php53
    make PREFIX=/usr/local/php53  PHPBASE =/usr/local/php53 install
    


    PREFIX — явно прописываем куда собирать PHP.
    PHPBASE — указываем базовую директорию PHP.
    После установки php, нужно установить extensions (расширения):
    cd /usr/ports/lang/php53-extensions
    make PREFIX=/usr/local/php53 PHPBASE=/usr/local/php53 install
    


    Во время сборки расширений если в системе не хватало каких то зависимостей оно их установит, но не в стандартные директории, а все туда же в /usr/local/php53, если заметите такие приложения то их нужно снести и поставить обычным способом.
    Вообще-то лучше ставить каждое расширение отдельно, это конечно долго и неприятно, но легче с обновлениями.
    После установки портов, в принципе все готово! Чтоб проверить все ли работает нормально выполняем:
    /usr/local/php5.3/bin/php-cgi -v
    

    покажет версию php

    /usr/local/php 5.3/bin/php-cgi -m
    

    покажет все установленные расширения, если ошибок нет, то все стало нормально.

    После этого ставим все нужные версии PHP в нужные нам папки

    Модуль на perl.
    Сам модуль должен лежать в
    cd /usr/local/ispmgr/addon
    


    Назовем его test.pl
    touch test.pl
    chmod +x test.pl
    chmod 700 test.pl
    


    По поводу модуля — можно много чего правильней написать, но делался он для того чтобы работать а не для красоты.
    Для использования модуля Вам нужно будет задать свои переменные (что и где лежит у Вас на сервере):
     #Путь к хомякам
     my $defhomedir = "/hosting";
     #Путь к php-cgi версии 5.2
     my $v52 = "#!/usr/local/php/52/bin/php-cgi";
     #Путь к php-cgi версии 5.3 (в данном случае установленная с панелью сразу)
     my $v53 = "#!/usr/local/bin/php-cgi";
     #Путь к php-cgi версии 5.4
     my $v54 = "#!/usr/local/php/54/bin/php-cgi";
     #Путь к php-cgi версии 5.5
     my $v55 = "#!/usr/local/php/55/bin/php-cgi";
     #Путь к врапперу пользователя
     my $wrapper = "".$defhomedir."/php-bin/"."$user"."/php";
     #print "(".$wrapper.")";
     open my $wrapperfile, '<', $wrapper;
     my $usercurrentphpwrapper = <$wrapperfile>;
     $usercurrentphpwrapper =~ s/\R//g;
     #print "(".$usercurrentphpwrapper.")";
     close $wrapperfile;
    


    Может и добавить:
    #Путь к php-cgi версии 5.6
    my $v56 = "#!/usr/local/php/56/bin/php-cgi"
    

    И соответственно обработку для версии:
    elsif ($usercurrentphpwrapper eq $v56)
     {
     $usercurrentphpver = "5.6";
     #print 'OK 56';
     }
    

    и
    elsif ($newphpver == 5.6)
     {
     system ("chflags noschg $defhomedir/php-bin/$user/php");
     system ("echo '#!/usr/local/php/56/bin/php-cgi' > $defhomedir/php-bin/$user/php");
     system ("chflags schg $defhomedir/php-bin/$user/php");
     system ("pkill -9 -u $user");
     $newphpver1 = 5600;
     #$usercurrentphpver = "5.6";
     #print 'OK 56';
     }
    


    Сам код модуля:
    #!/usr/bin/perl
     use CGI;
     use LWP::UserAgent;
     use CGI::Carp qw(fatalsToBrowser);
     use LWP::UserAgent;
     use Time::localtime;
    
     #take a time
     sub timestamp {
       my $t = localtime;
             return sprintf( "%04d-%02d-%02d_%02d-%02d-%02d",
             $t->year + 1900, $t->mon + 1, $t->mday,
                 $t->hour, $t->min, $t->sec );
                               }
     #end take a time              
    
     #isp get data
     my $Q = new CGI;
     open DATA, "<var/user.phpver";
     my @rows = <DATA>;
     close DATA;
     my $user = $ENV{"REMOTE_USER"};
      
     if ($Q->param("sok")) {
            open DATA, ">var/user.phpver";
            foreach $row (@rows) {
                my @elems = split / /, $row, 2;
                printf DATA "%s", $row if ($elems[0] ne $user);
            }
            printf DATA "%s %s\n", $user, $Q->param("phpver");
            close DATA;
      
            print "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<doc/>\n";
     } else {
            print "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<doc>\n";
      
            foreach $row (@rows) {
                chomp($row);
                my @elems = split / /, $row, 2;
                if ($elems[0] eq $user) {
     $elems[1] =~ s/\R//g;
                    print "<phpver>$elems[1]</phpver>\n";
                    last;
                }
            }
      
            # Заполняем список возможных версий
            print "<slist name=\"phpver\">\n";
            open WLIST, "<etc/phpver.list";
            my @wlist = <WLIST>;
            close WLIST;
            foreach $phpver (@wlist) {
                my @elems = split / /, $phpver, 2;
            $elems[0] =~ s/\R//g;
                print "<msg>$elems[0]</msg>\n";
            }
            print "</slist>\n";
      
            print "</doc>\n";
     }
     # END isp get data
    
     #Путь к хомякам
     my $defhomedir = "/hosting";
     #Путь к php-cgi версии 5.2
     my $v52 = "#!/usr/local/php/52/bin/php-cgi";
     #Путь к php-cgi версии 5.3 (в данном случае установленная с панелью сразу)
     my $v53 = "#!/usr/local/bin/php-cgi";
     #Путь к php-cgi версии 5.4
     my $v54 = "#!/usr/local/php/54/bin/php-cgi";
     #Путь к php-cgi версии 5.5
     my $v55 = "#!/usr/local/php/55/bin/php-cgi";
     #Путь к врапперу пользователя
     my $wrapper = "".$defhomedir."/php-bin/"."$user"."/php";
     #print "(".$wrapper.")";
     open my $wrapperfile, '<', $wrapper;
     my $usercurrentphpwrapper = <$wrapperfile>;
     $usercurrentphpwrapper =~ s/\R//g;
     #print "(".$usercurrentphpwrapper.")";
     close $wrapperfile;
    
    
     if ($usercurrentphpwrapper eq $v53) {
     $usercurrentphpver = "5.3";
     #print 'OK 53';
     }
     elsif ($usercurrentphpwrapper eq $v52)
     {
     #print 'OK 52';
     $usercurrentphpver = "5.2";
     }
     elsif ($usercurrentphpwrapper eq $v54)
     {
     $usercurrentphpver = "5.4";
     #print 'OK 54';
     }
     elsif ($usercurrentphpwrapper eq $v55)
     {
     $usercurrentphpver = "5.5";
     #print 'OK 55';
     }
    
     #Смотрим что выбрано
     my $newphpver = $Q->param("phpver");
     #$newphpver =~ s/\R//g;
    
     #Список пользователе которым запрещено менять версию  !!!! Важно так как используется pkill -9 -u $user процессы рута из под рута не прибить бы
     my $disuser1 = "USER";
     my $disuser2 = "root";
    
    
     if ( $user eq $disuser1 ) {
     $www111 = "off - USER";
     system ("echo 'restricted user USER' >> /usr/local/ispmgr/var/phpver.change");
     }
     elsif ( $user eq $disuser2 ) {
     $www111 = "off - root";
     system ("echo 'restricted user root' >> /usr/local/ispmgr/var/phpver.change");
     }
    
    
     #Обработка выбранных значений
     elsif ($newphpver == 5.3) {
     $newphpver1 = 5300;
     #Снимаем флаг 
     system ("chflags noschg $defhomedir/php-bin/$user/php");
     #Записываем во враппер пользователя новый путь к выбранной верии PHP
     system ("echo '#!/usr/local/bin/php-cgi' > $defhomedir/php-bin/$user/php");
     #Ставим флаг обратно
     system ("chflags schg $defhomedir/php-bin/$user/php");
     #Убиваем все процессы пользователя
     system ("pkill -9 -u $user");
     #print 'OK 53';
     }
     elsif ($newphpver == 5.2)
     {
     system ("chflags noschg $defhomedir/php-bin/$user/php");
     system ("echo '#!/usr/local/php/52/bin/php-cgi' > $defhomedir/php-bin/$user/php");
     system ("chflags schg $defhomedir/php-bin/$user/php");
     system ("pkill -9 -u $user");
     #print 'OK 52';
     $newphpver1 = 5200;
     #$usercurrentphpver = "5.2";
    
    
     }
     elsif ($newphpver == 5.4)
     {
     system ("chflags noschg $defhomedir/php-bin/$user/php");
     system ("echo '#!/usr/local/php/54/bin/php-cgi' > $defhomedir/php-bin/$user/php");
     system ("chflags schg $defhomedir/php-bin/$user/php");
     system ("pkill -9 -u $user");
     $newphpver1 = 5400;
     #$usercurrentphpver = "5.4";
     #print 'OK 54';
     }
     elsif ($newphpver == 5.5)
     {
     system ("chflags noschg $defhomedir/php-bin/$user/php");
     system ("echo '#!/usr/local/php/55/bin/php-cgi' > $defhomedir/php-bin/$user/php");
     system ("chflags schg $defhomedir/php-bin/$user/php");
     system ("pkill -9 -u $user");
     $newphpver1 = 5500;
     #$usercurrentphpver = "5.5";
     #print 'OK 55';
     }
    
    # Запишем в лог
     open (MyFile, ">>" , "var/phpver.change") ;
     print MyFile '[' . timestamp() . '] '.$user.' php was '.$usercurrentphpver.' become '.$newphpver."\n";
     close MyFile;
    


    Далее нужно добавить возможность пользователям переключать версии (добавить пункт в настройках аккаунта).
    В папку
    cd /usr/local/ispmgr/etc
    


    Создаем файл ispmgr_mod_phpver.xml
    touch ispmgr_mod_phpver.xml
    chmod 700 ispmgr_mod_phpver.xml
    


    В нем впиливаем в меню «Настройки» ISPmanager выпадающее меню переключения версий:

    <?xml version="1.0" encoding="UTF-8"?>
     <mgrdata>
         <handler name="test.pl" type="cgi">
           <event after="yes">usrparam</event>
         </handler>
         <metadata name="usrparam">
             <form>
                <field name="phpver">
                   <select name="phpver"/>
                </field>
             </form>
         </metadata>
         <lang name="en">
             <messages name="usrparam">
                 <msg name="5.3">5.3</msg>
                 <msg name="5.2">5.2</msg>
                 <msg name="5.1">5.1</msg>
                 <msg name="4.4">4.4</msg>
             </messages>
         </lang>
         <lang name="ru">
             <messages name="usrparam">
                 <msg name="phpver">Версия PHP </msg>
                 <msg name="hint_phpver">Предпочитаемая версия PHP.</msg>
             </messages>
         </lang>
     </mgrdata>
    


    Тамже в /usr/local/ispmgr/etc создаем файл
    touch phpver.list
    

    В нем перечень версий что будем использовать и установлены на сервере
    5.2
    5.3
    5.4
    5.5
    
    

    Не забываем ставить перевод каретки (обратите внимание на пустую строку под 5.5).
    Создаем файл в:
    cd /usr/local/ispmgr/var/
    

    Файл phpver.change:
    touch phpver.change
    chmod 700 phpver.change
    


    Сюда будет падать лог изменения пользователями версий.
    Чистим xml кеш ISPmanager
    rm -rf /usr/local/ispmgr/var/.xmlcache
    

    Перезапускаем панель ISPmanager:
    killall ispmgr
    


    Проверяем на тестовом пользователе
    <?
    phpinfo();
    ?>
    


    Заходим в ISPmanager и пользуемся. Также не забудьте отправить пользователям рассылку о доступности новой «плюшки».
    image
    Если что то забыл описать — добавлю.

    Про флаги FreeBSD в скрипте
    system («chflags noschg $defhomedir/php-bin/$user/php»);
    system («echo '#!/usr/local/php/52/bin/php-cgi' > $defhomedir/php-bin/$user/php»);
    system («chflags schg $defhomedir/php-bin/$user/php»);
    ISPmanager в старых версиях враппер записывал к пользователю в домашнюю директорию. Как следствие, если пользователь удалил все, то apache при перезапуске лег, так как враппера уже нет, поэтому ставим флаг неизменяемости.
    Для Centos chflags noschg заменить на chattr -i и соответственно chflags schg на chattr +i.

    Для CL если используется alt-php вместо:
    system ("echo '#!/usr/local/php/52/bin/php-cgi' > $defhomedir/php-bin/$user/php");
    

    Нужно указать:
    system ("cl-selector -s php -v $newphpver -u $user");
    
    Поделиться публикацией

    Похожие публикации

    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 13

      +2
      Извините, но в приличном обществе за такой код бьют по рукам.
      Да, вы написали:
      По поводу модуля — можно много чего правильней написать, но делался он для того чтобы работать а не для красоты.

      С другой стороны, этот код — почти половина статьи.
      То есть, вы как бы говорите: у меня полстатьи не очень.
      Если можно написать правильнее, то почему бы и не написать? Сами же потом разбираться в нем будете.
        –5
        Код делался максимально простой для понимания и расширения (увеличения) версий для переключения.
          0
          Это сложно назвать простым кодом. Практически все тут направлено на нарушение принципа DRY.
          Код

          system ("chflags noschg $defhomedir/php-bin/$user/php");
          system ("echo '#!/usr/local/php/55/bin/php-cgi' > $defhomedir/php-bin/$user/php");
          system ("chflags schg $defhomedir/php-bin/$user/php");
          system ("pkill -9 -u $user");
          $newphpver1 = 5500;
          

          повторяется во всех условиях. При этом отличие одного блока от другого только в пути и в переменной. Не проще было сделать switch/case с нужными версиями (или проверку версии в заранее заданном массиве) и объявить функцию change_version?
          Что-то вроде:

          switch ($newphpversion) {
              case 5.4:
              case 5.3:
              ...
                  change_version($newphpversion);
                  break;
              default:
                  throw new Exception("Unknown version");
          }
          

          Код PHP, с перлом не знаком, но конструкция switch/case там точно есть.
          Вместо этого вы даже поленились убрать закомментированный устаревший код.
            +1
            switch/case в языке нету, к сожалению. Только модулями.
              +1
              А массивы? И поиск по значению?
              Что-то типа питоновского:
              available_versions = [5.1, 5.2, 5.3, 5.4]
              
              if newphpversion in array:
                  change_version(version = newphpversion)
              else:
                  raise("Unknown version")
              
                +1
                Поиска в массиве стандартно нету, но обычно реализуется хэшем, например, так:
                my $available_versions = { "5.1" => 1, "5.2" => 1, "5.3" => 1, "5.4" => 1 }
                
                my $required_version = "5.4"
                
                А потом:
                if ( defined $available_versions->{ $required_version } ) {
                
                } else {
                
                }
                
                  +1
                  Ну вот и отлично! Значит, код действительно можно улучшить :) Было бы желание.
                    +1
                    Я бы сказал, что этот код бесконечно улучшабилен :)
          –1
          Закомментированные строки оставлены преднамеренно. Чтобы при отладке на сервере можно было вывести во временный файл логов нужные переменные и отслеживать обработку.
          По поводу сделать switch/case это ближе кодерам а не админам. Админам проще видеть команды CLI, которые выполняются. Многие хостеры не имея аналогичного модуля просто вручную переключат версии подменой враппера.
            +1
            Да пусть они живут у вас, эти строки. При публикации статьи-то их можно было удалить, ценности они не несут. Кто захочет отладочную информацию — поставит их сам.
            А любой хороший админ, имхо, и так должен быть немножко кодером, капельку бухгалтером, хорошим эникеем и немножко волшебником.
              +1
              Золотые слова :)
            0
            За Perl код без use strict или use warnings нужно линчевать.
              0
              Для тех, кто будет искать через поисковик — в версии ISPmanager Lite PHP selector доступен начиная с версии 5.30
              Вот новость на сайте компании https://www.ispsystem.ru/news/php-selector

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

              Самое читаемое