Ответы пользователя по тегу PHP
  • В чем проблема Catch блока?

    @dzhebrak
    Функция require выдает ошибку, а не бросает исключение, поэтому обрабатывать ее нужно с помощью функций set_error_handler и register_shutdown_function

    function myErrorHandler($errno, $errstr, $errfile, $errline)
    {
    	print "<pre>"; print_r($errstr); print "</pre>";
    }
    
    function myShutdownHandler()
    {
    	print "<pre>"; print_r(error_get_last()); print "</pre>";
    
    }
    
    set_error_handler('myErrorHandler');
    register_shutdown_function('myShutdownHandler');
    
    //Require-скрипты

    Лучше проверять, есть ли файл, который хотите подключить (с помощью file_exists()) и после этого уже подключать его.
    Ответ написан
  • Как создать установщик для php скрипта?

    @dzhebrak
    Посмотрите, как делают, к примеру, в wordpress: https://github.com/WordPress/WordPress/blob/master...

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

    Шаги задаются в зависимости от того, какие исходные данные необходимы для работы вашего скрипта. Это могут быть, к примеру, проверка системных требований (версия php, включенные модули и т.д.), доступы к базе данных, пользователь по умолчанию и т.д..
    Ответ написан
    Комментировать
  • Почему php не видит переменную?

    @dzhebrak
    В функции make_upload вы изменяете локальную версию переменной $ava, т.е. ту, которая доступна только в пределах функции make_upload.

    Вы можете использовать ключевое слово global в функции make_upload, чтобы изменить значение глобальной переменной $ava:
    function make_upload($file){
        global $ava;
        $ava = $href;
        // ...
    }

    Здесь можно почитать про области видимости переменных https://www.php.net/manual/ru/language.variables.s...
    Ответ написан
    4 комментария
  • Почему array_flip не верно отрабатывает?

    @dzhebrak
    У вас в массиве после array_column много одинаковых значений, но с разными ключами. array_flip для таких значений возвращает последний найденный ключ (например, 12856 вместо 32 в вашем случае).

    Если значение встречается несколько раз, для обработки будет использоваться последний встреченный ключ, а все остальные будут потеряны.

    https://www.php.net/manual/ru/function.array-flip.php
    Ответ написан
    1 комментарий
  • Как обновить столбец в БД?

    @dzhebrak
    Указанный код корректный.
    Проверьте, что в $_POST действительно передаются id и carname:
    print("<pre>");print_r($_POST);print("</pre>");

    Если есть такие ключи, то указанный вами код попробуйте заменить на следующий:
    $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
    
    $sql = 'UPDATE `cars` SET `name` = :carname WHERE `id` = :id';
    $s = $db->prepare($sql);
    $s->bindValue(':id', $_POST['id']);
    $s->bindValue(':carname', $_POST['carname']);
    $s->execute();
    
    print("<pre>");print_r($s->errorInfo());print("</pre>");

    Так будет показана ошибка, которая возникла при запросе.
    Ответ написан
    1 комментарий
  • Notice при выводе массива с помощью foreach в html?

    @dzhebrak
    Исправленный вариант:
    <div>
      <?php foreach($images as $img): ?>
            <img src="images/<?=$img?>" alt="" width="200">
        <?php endforeach; ?>
    </div>

    Обратите внимание на открывающие теги: <?php вместо <?. Чтобы использовать второй вариант (как в вашем примере) в php.ini параметр short_open_tag должен быть равен On
    Ответ написан
    3 комментария
  • Что я делаю не так с file_get_contents?

    @dzhebrak
    Вероятно на странице два блока пагинации, которые соответствуют указанному регулярному выражению.

    По умолчанию в preg_match_all передается флаг PREG_PATTERN_ORDER

    PREG_PATTERN_ORDER
    Упорядочивает результаты так, что элемент $matches[0] содержит массив полных вхождений шаблона, элемент $matches[1] содержит массив вхождений первой подмаски и т.д.

    Поэтому в $pages[0] указаны все вхождения шаблона, а в $pages[1] - вхождения первой подмаски (номер страницы в вашем случае).
    Ответ написан
    Комментировать
  • Как вывести древовидную структуру из массива?

    @dzhebrak
    $arr = [
    	['id' => 1, 'sub_id' => null, 'name'=> 'name1'],
    	['id' => 2, 'sub_id' => 1,    'name'=> 'name2'],
    	['id' => 3, 'sub_id' => 1,    'name'=> 'name3'],
    	['id' => 4, 'sub_id' => null, 'name'=> 'name4'],
    	['id' => 5, 'sub_id' => 2,    'name'=> 'name5'],
    	['id' => 6, 'sub_id' => 4,    'name'=> 'name6'],
    ];
    
    /* https://stackoverflow.com/a/28429487  */
    function buildTree(array &$elements, $parentId = 0) {
    
        $branch = array();
    
        foreach ($elements as &$element) {
    
            if ($element['sub_id'] == $parentId) {
                $children = buildTree($elements, $element['id']);
                if ($children) {
                    $element['children'] = $children;
                }
                $branch[$element['id']] = $element;
                unset($element);
            }
        }
        return $branch;
    }
    
    function printTree(array $arr, $level=1) {
    	foreach ($arr as $k => $v) {
    		print(str_repeat('-', $level) . $v['name'] ."\n");
    		if(isset($v['children']) && is_array($v['children'])) {
    			printTree($v['children'], $level + 1);
    		}
    	}
    }
    
    printTree(buildTree($arr));
    Ответ написан
    Комментировать
  • Почему ajax возвращает null?

    @dzhebrak
    session_start() или стартует новую сессию, либо возобновляет существующую. Для второго варианта php должен знать идентификатор сессии, который или хранится в cookies (PHPSESSID), или передается как параметр url. В случае запроса с помощью fetch вы не передаете ни первое, ни второе, поэтому php начинает новую чистую сессию, в которой переменная logged не определена.

    https://www.php.net/manual/ru/session.examples.bas...
    Ответ написан
    2 комментария
  • Как сформировать приоритет в php массиве?

    @dzhebrak
    Кроме usort/uasort можно разбить ссылки на отдельные массивы, а затем собрать обратно в один, который и перебрать с помощью foreach:

    $arr = [
    	["small"=> "/images/0001_GOLD.jpg"],
      	["small"=> "/images/003_lux.jpg"],
      	["small"=> "/images/002_prod_3.jpg"],
      	["small"=> "/images/0002_GOLD.jpg"],
      	["small"=> "/images/002_prod_5.jpg"],
      	["small"=> "/images/002_lux.jpg"],
      	["small"=> "/images/002_prod_4.jpg"],
    ];
    
    $lux = [];
    $prod = [];
    $gold = [];
    
    foreach ($arr as $v) {
    	if(strpos($v['small'], 'lux') !== false) {
    		$lux[] = $v;
    	}
    
    	if(strpos($v['small'], 'prod_') !== false) {
    		$prod[] = $v;
    	}
    
    	if(strpos($v['small'], 'GOLD') !== false) {
    		$gold[] = $v;
    	}
    }
    
    print_r(array_merge($lux, $prod, $gold));
    Ответ написан
    Комментировать
  • Почему возникает ошибка Permission denied при удалении файла PHP?

    @dzhebrak
    Проверьте права именно у файла .htaccess. Часто для него дополнительно ограничивают права.

    Еще возможная причина - SELinux
    Ответ написан
  • Что такое @param в php?

    @dzhebrak
    https://docs.phpdoc.org/latest/references/phpdoc/t...

    Тег @param используется для документирования аргумента функции или метода. В основном для улучшения автокомплита в ide.

    Непосредственно на функционал он не влияет
    Ответ написан
    Комментировать
  • Php file_get_contents получаю данние о валюте но страница дольго грузится какое есть решение?

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

    Учитывая, что указанная страница возвращает код 500, то вероятнее всего есть какая-то проблема на стороне сервера, с которого получаете данные. Если доступов к нему нет, то исправить нет возможности.

    Есть 2 возможных варианта решения проблемы:

    1. кэшировать полученные данные, к примеру, на 1-5 минут. Соответственно, если данные есть в кэше, и они не устарели, то возвращаем их; в противном случае делаем запрос к указанному сервису.

    2. написать скрипт, который будет обновлять данные раз в минуту по крону и сохранять куда-то, а на сайте выводить уже сохраненные ранее данные.
    Ответ написан
  • Почему пропадает абсолютный путь к фотографии?

    @dzhebrak
    Вы нигде не добавляете текущий домен в переменную $file_url, поэтому в ней указан относительный путь.

    Для получения текущего домена можно использовать $_SERVER['HTTP_HOST']

    PS. Лучше (по крайней мере для начинающих) использовать готовые фреймворки - в них обычно подобный функционал уже реализован. Также вы будете видеть best practices, да и поддерживать такой код в дальнейшем будет проще.
    Ответ написан
  • Как оптимизировать сложные проверки в Entity?

    @dzhebrak
    Как вариант, можно вынести только проверку в отдельный сервис в доменном слое (Domain Layer), и этот сервис передавать как аргумент в метод add() вашей сущности. Если этот сервис бросит исключение, то метод add прекращает выполнение. В сервис передавать в конструкторе репозиторий или другой объект, который подгрузит необходимые для проверки данные.

    Далее вынести вызов метода add() в сервис на уровне приложения (Application Layer), как вы написали, в котором и передавать ранее созданный сервис проверки в метод add().

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

    Пример:
    class Entity
    {
    	public function add(ComplexEntityValidator $validator) {
    		$validator->validate();
    	}
    }
    
    class ComplexEntityValidator
    {
    	public function __construct(EntityRepository $repository) {
    
    	}
    
    	public function validate() {
    		// проверка
    	}
    }
    
    class EntityApplicationService
    {
    	public function __construct(ComplexEntityValidator $validator) {
    
    	}
    
    	public function __invoke() {
    		$entity = new Entity();
    		$entity->add($validator);
    		// сохранение сущности
    	}
    }
    Ответ написан
    3 комментария
  • Как сделать очередь на PHP по работе с CRM системой?

    @dzhebrak
    Готовых вариантов для динамического создания воркеров, к сожалению, нет (или по крайней мере я никогда не сталкивался с такими). Можно сделать следующим образом.

    В базе данных сделайте таблицу для очереди, в которой одним из столбцов будет номер аккаунта клиента.
    При получении вебхука не обрабатывайте (т.е. не делайте запросы к crm) его сразу, а только сохраняйте в вышеуказанную таблицу.
    Напишите скрипт, который будет запускаться раз в минуту по крону. Этот скрипт должен получить уникальные аккаунты (DISTINCT) из таблицы очереди и запустить все обработчики, каждый из которых будет обрабатывать только 1 аккаунт клиента (т.е. аккаунт передается обработчику как аргумент). Запускать нужно как фоновый процесс (&). Можно перед запуском проверять, не запущены ли они уже, или сделать это на следующем шаге.
    Обработчик при старте проверяет, не запущен ли другой его экземпляр для этого же клиента. Затем до тех пор, пока есть записи в очереди именно для этого аккаунта, скрипт получает по 7 записей для этого аккаунта, и по ним делает 7 одновременных запросов к api crm с помощью guzzle docs.guzzlephp.org/en/stable/quickstart.html#concu... , после чего удаляет записи из очереди.

    Альтернативным вариантом будет использование очереди вроде RabbitMQ вместо базы данных. Нужно будет в exchange создать очередь для каждого аккаунта клиента, и также скриптом по крону получать информацию по тому, какие есть очереди и запускать обработчиков. Первый способ, на мой взгляд, проще, да и его будет достаточно, если вы не обрабатываете миллионы записей ежедневно.
    Ответ написан
    3 комментария
  • MySQL как создать если не существует?

    @dzhebrak
    Сделайте уникальный индекс по этим трем столбцам https://www.mysqltutorial.org/mysql-unique/ , а при записи используйте ON DUPLICATE KEY UPDATE https://www.mysqltutorial.org/mysql-insert-or-upda...
    Ответ написан
    2 комментария
  • Как проверить значения массива на схожесть?

    @dzhebrak
    Еще одно решение - вычислить расстояние Левенштейна между строками https://www.php.net/manual/ru/function.levenshtein.php

    Расстояние Левенштейна - это минимальное количество вставок, замен и удалений символов, необходимое для преобразования str1 в str2. Сложность алгоритма равна O(m*n), где n и m - длины строк str1 и str2 (неплохо по сравнению с similar_text(), имеющей сложность O(max(n,m)**3), но все же довольно много).

    echo(levenshtein('abcdefg', 'amcdehg'));
    Если расстояние между строками равно 2, значит нужно вставить, заменить или удалить 2 символа, соответственно строки похожи.

    Функция для работы с русским языком: https://gist.github.com/shankao/b0d92e15c65852fda481

    Пример:
    $lines = [
      'Продам клинок демона +6 / Солнцеликий плащ +2 тьма',
      'Продам клинок демона +6, Солнцеликий плащщ +2тьма',
      'Акция! Продам клинок демона +6, Солнцеликий плащ +2тьма',
      'Продам клинок ангела +3, Луноликая куртка +4свет',
      'Продам клинок ангелла +3, Луноликая куртка +4свет',
      'Акция ! Продам клинок ангела +3, Луноликая куртка +4свет',
      'тест акции',
      'проверка демона',
      'проверка ангела',
    ];
    
    $res = [];
    $allSimilar = [];
    
    foreach ($lines as $line) {
        $similarLines = [];
    
        if(in_array($line, $allSimilar)) {
            continue;
        }
    
        foreach ($lines as $line1) {
            $lev = mb_levenshtein($line, $line1);
            $maxDistance = (int)(0.2 * max(mb_strlen($line), mb_strlen($line1)));
    
            if($lev <= $maxDistance) {
                $similarLines[] = $line1;
                $allSimilar[] = $line1;
            }
        }
    
        $res[$line] = $similarLines;
    }
    
    print_r($res);

    Похожими считаются фразы, которые отличаются менее чем на 20% их длины.
    Ответ написан
    Комментировать
  • PHP, как решить конфликт множественного использования trait?

    @dzhebrak
    Как вариант, в OtherFirstTrait и OtherSecondTrait можно не использовать ErrorTrait, а сделать абстрактный метод с той же сигнатурой, что и в ErrorTrait. В ChildClass в свою очередь использовать ErrorTrait, OtherFirstTrait, OtherSecondTrait.

    Пример:
    trait ErrorTrait
    {
    	public function someMethod($someArg) {
    		echo __TRAIT__ . ": " . $someArg . "\n";
    	}
    }
    
    trait OtherFirstTrait
    {
    	abstract public function someMethod($someArg);
    
    	public function someMethod1($someArg) {
    		echo __TRAIT__ . ": " . $someArg . "\n";
    		$this->someMethod($someArg);
    	}
    }
    
    trait OtherSecondTrait
    {
    	abstract public function someMethod($someArg);
    
    	public function someMethod2($someArg) {
    		echo __TRAIT__ . ": " . $someArg . "\n";
    		$this->someMethod($someArg);
    	}
    }
    
    abstract class MainClass
    {
    	use ErrorTrait;
    }
    
    class ChildCLass extends MainClass
    {
    	use OtherFirstTrait, OtherSecondTrait;
    }
    
    $o = new ChildCLass();
    $o->someMethod("test ErrorTrait");
    print("\n");
    $o->someMethod1("test OtherFirstTrait");
    print("\n");
    $o->someMethod2("test OtherSecondTrait");

    Вывод:
    ErrorTrait: test ErrorTrait
    
    OtherFirstTrait: test OtherFirstTrait
    ErrorTrait: test OtherFirstTrait
    
    OtherSecondTrait: test OtherSecondTrait
    ErrorTrait: test OtherSecondTrait
    Ответ написан
    3 комментария