Ответы пользователя по тегу PHP
  • (Unicode) Как сжать код?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    function mb_str_split($string) {
        return array_map(function ($i) use ($string) {
              return mb_substr($string,$i,1,"utf-8");
        }, range(0, mb_strlen($string, "utf-8")-1));
    }
    
    function incode($string) {
    	return array_reduce(mb_str_split($string), function($result, $e) {
    		$convertedString = unpack("N", mb_convert_encoding($e, "UCS-4BE", "UTF-8"));
                    return $result . (is_array($convertedString) ? $convertedString[1] : '');
    	}, "");
    }
    Ответ написан
  • Есть ли где то учебник или видео курс по процедурному программирования PHP на руссском?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    php.net/manual/ru/index.php как не странно. фэнси паттерны и бэст практис это обычно ООП в контексте php. Можете поискать литературу по Си, поскольку там нету объектов а есть только структуры и функции, это наиболее близко к тому что вы пытаетесь сделать.
    Ответ написан
  • Создание лицензии для движка, что прочитать?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    Я решил взяться за это дело нормально и подарить миру нормальную cms.

    Удачи. Получится как обычно.

    Не рассматривали схему, которую выбрали всякие gitlab, магенты и и т.д.? open-source + энтерпрайз редакции + суппорт.
    Ответ написан
    1 комментарий
  • How PHP array to schema of MySQL table?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    Это уже есть в doctrine/migrations + doctrine/orm. Можно просто взять doctrine/migrations и dbal и сделать универсальный инструмент.

    p.s. использую doctrin/migrations постоянно, миграции схемы дифами это круто.
    Ответ написан
  • Можно ли убрать этот ватермак?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    Чисто теоритически - возможно но думаю дешевле будет нанять школьников/студентов, которые будут вручную это добро обрабатывать.

    updated:
    google images умеет искать по изображению.
    Ответ написан
    Комментировать
  • Как настроить зависимости для проекта через composer?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    composer умеет работать с GIT репозиториями. Вам просто в composer.json каждого проекта придется прописать репозиторий для этого пакета.

    Подробнее в документации. https://getcomposer.org/doc/04-schema.md#repositories
    Ответ написан
    Комментировать
  • Как сделать Router для PHP фреймфорка?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    По поводу инклудов - читаем про PSR-0/PSR-4 автозагрузку.

    $className = sprintf('\MyCoolFramework\Module\%s\Controller', $this->modul);
    // подключать не нужно, для этого нужен автозагрузчик 
    // который из неймспеса и названия класса сгенерит вам путь к файлу и подключит его
    // некрасивый способ
    $controller = new $className();
    // красивый способ, но медленный, зато с плюшками
    $class = new ReflectionClass($className);
    $controller = $class->newInstance();


    Плюшки метода с рефлексиями в том, что вы можете:
    1) Узнать есть ли какие-то требования у контроллера в плане аргументов конструктора и предоставть ему зависимости
    2) достать метод из класса который вы хотите вызвать, получить список аргументов и попытаться сопоставить имеющиеся данные с этими аргументами.
    3) запускать метод экшена так же стоит рефлексией, и достать рефлексию нужного метода (и проверить что он есть) этим методом проще.

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

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    Я слегка к вечеру начал туго соображать, но давайте попробуем. Возможно я допущу какое грубое невежество или моя версия алгоритма не слишком интересная... но мне откровенно лень много думать. Так что задачу я решу почти в лоб. Для начала определимся что мы должны сделать...

    $words = explode(' ', 'a b c d'); // сразу представим строку как массив для более удобной работы с оным
    $expectedResult = [
        // 1st level
        [
            'a b c d e',
        ],
        // 2-ой уровень
        [
            'a',
            'b c d e'
        ],
        [
            'a b',
            'c d',
        ],
        [
            'a b c',
            'd'
        ],
        // 3-ий уровень
        [
            'a',
            'b',
            'c d',
        ],
        [
            'a',
            'b c',
            'd'
        ],
        [
            'a b',
            'c',
            'd'
        ],
        // 4-ый уровень
        [
            'a',
            'b',
            'c',
            'd'
        ]
    ];


    каждый уровень представляет из себя комбинации предыдущего:
    то есть для строки "a b c d" первый элемент третьего уровня:
    [
        'a',
        'b',
        'c d'
    ]

    можно составить как конкатенацию первого элементов второго уровня строки 'b c d' с добавлением оторванной части
    ['a'] + ['b', 'c d']
    Следовательно можно упростить алгоритм введя рекурсию постоянно уменьшая сложность. Разделяй и влавствуй как говориться. Поскольку нас теперь заботят только элементы первого и второго уровня алгорим существенно упрощается (можно хоть 666 уровней делать, реализация от этого сложнее не становится. Единственный минус - на большой вложенности можно упереться в лимит по стэку - решается заменой стэка на очередь вызовов но это не здесь и не сейчас).

    Единственное о чем нам стоит подумать - о логике склеивания кусков и условия выхода из рекурсии.

    Допустим у нас 4 слова в строке. Нам нужно собрать все варианты элементов третьего уровня. Для этого нам надо:
    1) ['a'] + ['b', 'c d'] - есть наборы для строк "a" и "b c d"
    2) ['a'] + ['b с', 'd'] - есть наборы для строк "a" и "b c d"
    3) ['a b'] + ['c', 'd'] - есть наборы для строк "a b" и "c d"
    На третьем стэпе мы достигли ситуации, при которой у нас вторая часть строки содержит количество слов равной требуемому уровню (два слова для второго уровня). Собирать комбинации больше неизчего. Сделаем это нашим уловием выхода из цикла.

    Давайте теперь попробуем соорудить функцию, которая будет корректно отрабатывать первый и второй уровни

    function buildLevel(array $words, $level) {
        // с первым уровнем все просто
        if ($level === 1) return [implode(' ', $words)];
        if ($level === 2) {
            // со вторым чуть по сложнее...
            $result = [];
            $chunk = [];
            while(count($words) >= $level) {
                // отделяем первое слово из "строки" и зановим его к первому "слагаемому"
                array_push($chunk, array_shift($words));
                $result[] = array_merge([implode(' ', $chunk)], [implode(' ', $words)]);
            }
    
            return $result;
        }
    
        throw new \Exception(sprintf('Not implemented for level %d for now', $level));
    }


    Проверям работу: ideone.com/ggFzJd
    array(1) {
      [0]=>
      string(7) "a b c d"
    }
    array(3) {
      [0]=>
      array(2) {
        [0]=>
        string(1) "a"
        [1]=>
        string(5) "b c d"
      }
      [1]=>
      array(2) {
        [0]=>
        string(3) "a b"
        [1]=>
        string(3) "c d"
      }
      [2]=>
      array(2) {
        [0]=>
        string(5) "a b c"
        [1]=>
        string(1) "d"
      }
    }

    все ок, только результаты надо склеить.... Но давайте вспомним одно из основных правил программирования! DRY - do not repeat your self. Что мы видим? Одинаковый код! В обработке второго уровня у нас используется код, который мы уже использовали в обработке первого уровня! Причем дважды! Кошмар! Рефакторим...

    $result[] = array_merge(buildLevel($chunk, 1), buildLevel($words, 1));


    Теперь вспомним наш замысел... Мы хотели огранизовать рекурсию, и она родимая у нас и выходит. Функция вызывает самою себя понижая уровень. Сложность решения уменьшается, все хорошо. По такому же принципу добавляем обработку третьего уровня. Попробуйте сначала сами и самостоятельно попробуйте побороть проблему "склейки" результатов третьего и второго уровня. Зачем просто унифицируйте решения. Для того что бы поставить логическую точку, я все же предоставлю готовое решение, но постарайтесь все же сами сделать сначала:

    ideone.com/fwS4u6 - к сожалению времени не так много... может позже доделаю склейку. Пока так. Суть надеюсь будет ясна. Если кто допилит - буду рад.
    Ответ написан
  • Как Assetic внедрить в Twig?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    Эм... вы точно долистали документацию до конца?
    https://github.com/kriswallsmith/assetic#twig
    Ответ написан
    Комментировать
  • Как всё-таки оптимально импортировать из XLS в PHP?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    Разработчики по-моему слишком заморочились с поддержкой форматирования.

    а какой смысл тогда в библиотеке если оно не будет уметь основного?

    Можно сконвертить файлик в xlsx и потом уже работать с более шустрыми библиотеками или напрямую парсить xml с xpath.

    Если вам только данные вытащить нужно, можно вообще дампнуть в CVS.
    Ответ написан
    Комментировать
  • Как установить единую временную зону для php и mysql при старте сайта?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    php.net/manual/en/function.date-default-timezone-s... + записать в конфиг и восстанавливать нужное значение при запуске.

    А еще лучше, потыкать штуки типа ansible, из web интерфейса генерить чисто файлы с переменнми и потом выполнять ансиблом провиженингн окружения.
    Ответ написан
    Комментировать
  • Каким образом можно перехватить ошибку при выполнение автоматического теста с использованием Codeception и обработать эту ошибку нужным образом?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    ошибка выполняется не в тест-раннере а в приложении. 99% что приложение запускается отдельно и влиять на него через Codeception вы никак не можете. Так что это нужно разруливать как-то на уровне приложения. Либо в случае ошибки из логов вытягивать что случилось. Последнее пожалуй лучший вариант.
    Ответ написан
    Комментировать
  • Как передать переменную из встроенного скрипта во внешний?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    <?php $isEdit = 'Yes'; ?>
    <script type="text/javascript">
        window.isEditJS = <?=json_encode($isEdit); ?>; // что бы небыло потом проблем с типами и кавычками
    </script>
    <script src='/isedit.js'></script>
    Ответ написан
    1 комментарий
  • Асинхронная многопоточность в PHP: для чего?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    Все очень просто. Вот вам приблизительное значение таймингов доступа к данным:
    io-cost.png

    То есть запросив данные в сети мы тупо ждем. Долго ждем и ничего не делаем.

    В случае с curl (он же HTTP) мы можем соорудить очередь запросов и послать их одним махом и ждать пока завершится загрузка всех документов в очереди для обработки результатов. Если мы хотим забрать 10 документов, то без multi curl у нас ушло бы времени "среднее время получения документа" * 10. И это примерно. В случае же с мультикурлом мы получаем время обработки 10 запросов как время выполнения самого долгого запроса. Если представить что время запросов всегда одинаковое, получаем выйгрыш примерно в 10 раз.

    С сокетами веселее. Они бывают блокируемые (по умолчанию) и неблокируемые (выставляется опцией O_NONBLOCK). Для начала давайте определимся что такое чтение данных из сокетов и как нам это дело предоставляет операционная система. Упрощенно, когда мы создаем сокет, мы просто просим операционную систему предоставить оный. У каждого сокета есть буфер чтения и буфер записи. Если буфер записи полный - ОС начинает отправку данных пока буфер не опустеет (буфер записи нужен для организации проверки дошли ли пакеты и переотправки в случае чего, так же этот буфер замешан в выборе операционкой размеров пакетов и т.д. Это не особо важно в контексте вопроса). Когда данные приходят в сокет, сначала они помещаются в буфер чтения. Там они лежат пока их не попросят вернуть из кода. Так мы можем быть уверены в том, что данные не пропадут.

    Так вот... возьмем блокирующие сокеты и попробуем запросить 1024 байт данных из оного. Причем клиент в данный момент ничего не отправляет, буфер чтения пустой. И так допустим минут 10. Как только мы сделали запрос за данными, и оказалось что буфер чтения пустой, процесс выполнения блокируется пока не появятся данные.

    А теперь представим что проверять периодически наличие данных нам надо не в одном сокете а в десятке. Представим так же что 9 клиентов подключенных по нашим сокетам хорошие и присылают данные вовремя, а один не хороший и любит тупить по пол часа. Если бы мы пользовались блокирующими сокетами, то мы можем обрабатывать только одного клиента за раз. Причем если у него вдруг данных не оказалось - нам придется ждать, хотя в других сокетах уже вполне могли появиться данные какие для обработки. И если в случае с "хорошими" клиентами мы можем тратить на оных по пол секунды - секундочке, то наткнувшись на плохого клиента наш сервер замирает за те самые пол часа о которых мы договаривались. Сервер тупо ждет "плохого" клиента а хорошие в итоге не могут достучаться до сервера. Новых соединений мы так же не установим... короче все мертво.

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

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

    Еще есть такая чудная штука, которую предоставляет операционная система как select или epol (в контексте php socket_select и stream_select). Данные функции позволяют нам скармливать массивы сокетов, за которыми вы следите (не сокетов, а их дескрипторов но не суть, и не один массив а три, массив дескрипторов что бы следить появились ли данные на чтение, записал ли сокет все и освободился ли буфер записи и третий отслеживает сокеты в которых произошли какие-то ошибки, например отвалилось соединение). Так же этой функции можно задавать таймаут, что очень удобно если мы сначала собираем данные с нескольких клиентов и если от них небыло вестей пару секунд, значит мы забрали все и можно начинать обработку.

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

    Но все что выше имеет смысл только с TCP/TLS, если бы у нас были UDP сокеты, то было бы еще веселее. Там нету никаких буферов. Не принял данные - потерял данные. Нету соединений. Нету блокировок. Есть только пакеты. Поэтому этот протокол используют (или используют как основу) для реализации реалтайм систем. Задержек нету, а если какой пает не дошел, велика вероятность что он уже не актуален. Правда если сеть не надежная и потери пакетов велики, то начинается боль и слезы и обычно все же для таких случаев дублируют все на TCP.
    Ответ написан
  • Как сделать проверку на регулярные выражения?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    пук как-то не салидно, надо фарт.

    <?php
    
    if ('POST' === $_SERVER['REQUEST_METHOD']) {
        if (!empty($_POST['maria']) || !preg_match('/^\d+$/', $_POST['maria'])) {
             $age = intval($_POST['maria']);
             if ($age > 200) {
                   echo "столько не живут!";
             }
        } else {
             echo "возрост не введен!";
        }
    }
    ?>
    <meta charset="utf-8">
    <form method="post">
        введите свой возраст: <input type="text" name="puk">
    <input type="submit" name="maria" value="кукушка">
    </form>
    Ответ написан
    Комментировать
  • Сравнение списков, как лучше организовать?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    циклы, запросы и все такое... Вы бы описали как сравниваете.
    Ответ написан
    4 комментария
  • Какую выбрать тему для дипломной работы?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    если брать PHP то вот какие вещи нужны народу:
    - замена морально устаревшему phing-у (есть robo как альтернатива, но мне лично не очень нравится). Можно провести хорошую исследовательскую работу и составить решение достойное нынешних дней.
    - фабрики фикстур (framework-independent с возможностью интеграции). На данный момент существует только phactory из достойных (еще есть PHPMachinist из достойных). Есть мысль запилить авторесолвинг блупринтов для этих библиотек что бы было проще интегрировать в проект и рулить фикстурами. Так же можно продумать более упрощенное API для быстрой разработки. И да, ключевой момент тут - производительность и возможность ресетить все добавления в базу (что бы уменьшить время прогона тестов).

    Собственно вот... это то чего мне не хватает. Остальное относится с корее к тех-процессам. Скажем я пока не знаю как наладить процесс автоматизированного деплоя с ansible + docker (какую роль должен вы полнять ансибл) но тут не думаю что вы поможете. Хотя у моего знакомого темой диплома была тулза для конвертации форматов контейнеров для различных облачных сервисов. Может можно подумать и в этом направлении.
    Ответ написан
    2 комментария