Ответы пользователя по тегу PHP
  • Как сделать несколько вложенных джоинов?

    @alexalexes
    Сначала напишите чистый SQL:
    select n.*, -- атрибуты новости
               p1.*, -- атрибуты автора
               p2.*, -- атрибуты исполнителя
               s.* -- атрибуты статуса новости
    from news n
    join status s on s.statusId = n.statusId
    left join people p1 on p1.peopleId = n.authorId
    left join people p2 on p2.peopleId = n.executorId
    where p1.fullName like :search
           or p2.fullName like :search

    Потом откройте документацию по ORM и перепишите в методологии ORM.
    Сначала попробуйте простой запрос:
    select *
    from news

    Потом посмотрите, как делать join и работать с псевдонимами таблиц:
    select n.*, -- атрибуты новости
               s.* -- атрибуты статуса новости
    from news n
    join status s on s.statusId = n.statusId

    Потом как с where работать:
    select n.*, -- атрибуты новости
               s.* -- атрибуты статуса новости
    from news n
    join status s on s.statusId = n.statusId
    where s.statusId = :statusId

    Потом, как лайкать:
    select n.*, -- атрибуты новости
               p1.*, -- атрибуты автора
               p2.*, -- атрибуты исполнителя
               s.* -- атрибуты статуса новости
    from news n
    join status s on s.statusId = n.statusId
    left join people p1 on p1.peopleId = n.authorId
    where p1.fullName like :search

    И в заключение, как к лайкам добавить OR (самый первый запрос).
    Ответ написан
    Комментировать
  • Как правильно загружать картинки?

    @alexalexes
    Я нажимаю добавить картинку, она уходит на сервер, там ей присваивается новое уникальное имя,

    ... которое сервер тут же передает клиенту, как только файл гарантировано сохранился в хранилище (да, не обязательно, чтобы это был каталог сервера, он может загрузить файл через api облака, например, сам являясь клиентом системы хранения файлов).
    На клиенте, в скрытом поле вы собираете коллекцию уникальных имен файлов (идеально, если это будут id/guid/или другой род хеша).
    Когда пользователь удаляет файл, который был успешно отправлен серверу, можно отправить запрос, чтобы файл с таким-то идентификатором можно удалить, или поставить на удаление в очередь, если зачистка не сразу происходит.
    Когда пользователь сабмитит форму, тогда серверу передаются уникальные идентификаторы файлов, по которым сервер уже либо перемещает файлы на постоянное хранение, либо меняет их статус (файлы связывают с идентификатором поста, например).
    Те, файлы, которые остались в статусе черновика, скажем, в течение недели, можно зачистить скриптом, запускаемым по расписанию.
    Ответ написан
    Комментировать
  • Как передать значение переменной из JS в PHP без перезагрузки страницы?

    @alexalexes
    В php скриптах не обязательно всегда отдавать клиенту html-текст, тем более в виде статики (за пределами тегов <? ?>).
    А если вы еще используете ajax, обращаясь к тем же скриптам, что формируют полную html страницу, то можно отдавать ответ гораздо гибче (отдавать только чистые данные, без html в случае AJAX, и в остальных случаях - html оснастку, чтобы браузер нарисовал начальное состояние страницы):
    <?php
        if(isset($_POST['checkout']))
        {
          // получили параметр, который используется в AJAX - отдаем только данные (числа, строки, или json объекты)
           echo 'posted:'.$_POST['checkout'];
        }
       else
       {
         // не получили специфичных для ajax параметров - отдаем клиенту обычный HTML
          echo '<!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <div><?php echo $test ?></div>    
        <script type="text/javascript" src="js/jquery-3.6.0.min.js"></script>
        <script type="text/javascript" src="script.js"></script>
    
    </body>
    </html>';
       }
    ?>

    На этом строят API своей системы.
    Ответ написан
    Комментировать
  • Как исключить конкретный лейбл из генератора PDF?

    @alexalexes
    <?php echo $field_label == "название лейбла" ? "": $field_label; ?>

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

    @alexalexes
    $filtered_arr = array_filter($arr, function ($el) use ($arr2) { 
                return !in_array($el['number'], $arr2);
            }
        });

    В фильтрующей функции на return вы подаете выражение, которое можно перевести или трактовать как булевый результат true/false, по которому вы должны оставить поданный внутрь функции элемент $el в $filtered_arr.
    PS: Будьте осторожны с in_array - эта функция чувствительна к типу данных элемента и элементов массива, она их сравнивает как ===. Это на случай, если у вам в сравнении будут якобы числа, например, вместо 1010 будет '1010'.
    Ответ написан
    5 комментариев
  • Как отслеживать выход из сети?

    @alexalexes
    Чтобы реализовать вашу идею, нужен стек, где сервер выступает в роли ведущего по части отправки http-запроса клиенту. Сервер PHP, обычно, выступает в роли ведомого - когда клиент соизволит сделать запрос, тогда сервер может проанализировать, жив ли клиент. В случае с WebSocket можно на стороне сервера понять, закрылось ли соединение, не дожидаясь внятного ответа от клиента.
    Сервер PHP может в WebSocket, но реализации у него кривые. На эту роль идеально подходят NodeJS + WebSocket.
    С PHP вы только можете отслеживать, когда последний раз клиент отправлял запрос - если больше условных 10 минут назад, то он скорее мертв, чем жив.
    Ответ написан
    Комментировать
  • Некоторые бинарные строки не определяются по оператору LIKE, проблема не дебажится, в чём может быть причина?

    @alexalexes
    Вероятно, проблема в состоянии индекса на поле info_hash_v2 (вы же используете индексы в базе для ускорения поиска?). Запустите перерасчет индекса для устранения глюка.

    PS:
    $info_hash_where = "WHERE tor.info_hash = '$info_hash' OR tor.info_hash_v2 LIKE '$info_hash%'";

    Ай-ай-ай. Склейка параметров запроса с текстом запроса, ой не хорошо. Не хотите познакомиться с подготовленными запросами?
    Или нормально исследуйте класс объекта DB, вдруг там есть нормальный метод bind_param, а то вдруг используете инструмент не до конца по назначению.
    Ответ написан
  • Можно ли как либо защитить php-проект от "угона" другим наёмным программистом (фрилансером)?

    @alexalexes
    Меры безопасности такие же как и в любом коммерческом банке.
    1. Разделение информационной системы предприятия на контуры по готовности релиза: продакш (к управлению допускаются только ключевые технические специалисты компании), предпродакш (к управлению допускается только помощники ключевых технических специалистов, в контуре могут испытываться как тестовые данные, так и часть боевых данных), дев-контур для разработчиков (допускаются разработчики только по узкому направлению, в контуре циркулируют только тестовые данные).
    2. Разделение информационной системы предприятия по функционалу и делегирование прав доступа от рядового разработчика к ключевому специалисту в рамках одной подсистемы. Разработчики и их руководители должны иметь только те права доступа, которые необходимы для текущей работы.
    Ответ написан
    1 комментарий
  • Как сохранить get параметр при переходе на другую страницу?

    @alexalexes
    Если вы хотите сохранить выбранный населенный пункт в вашем разрабатываемом сайте (интернет магазине), то вам не нужно тянуть этот параметр при каждой ссылке. Вам нужно при выборе города от пользователя получить этот параметр один раз и сохранить его либо в куках $_COOKIE, либо в сессионной переменной в $_SESSION, либо в базе данных в профиле пользователя.
    Далее, при любом обращении к любой странице вашего сайта доставать этот параметр из описанных выше источников и использовать как некую переменную контекста для выбора и формирования контента страницы.
    Ответ написан
    1 комментарий
  • Если файл, содержащий пространство имён, сам подключает файл через 'include', какое в подключаемом файле будет пространство имён?

    @alexalexes
    Проверяйте на практике:
    echo '"', __NAMESPACE__, '"';
    https://www.php.net/manual/en/language.namespaces....
    Сами разберетесь быстрее и вопросов меньше будете задавать.
    Ответ написан
    Комментировать
  • Успешно! вместо текста?

    @alexalexes
    Браузеру пофигу на метазаголовки, если сервер пришлет http-заголовок с другой кодировкой.
    Нужно смотреть:
    1) в какой кодировке файл php (можно пересохранить в другой кодировке);
    2) какой браузеру приходит http-заголовок, связанный с кодировкой от сервера на вкладке Сеть по F12 (можно добавить http-заголовок с нужной кодировкой через функцию header);
    3) meta-заголовки кодировки бесполезны, если выводом контента рулит php-скрипт.
    Ответ написан
    Комментировать
  • Как прервать счетчик и продолжить отсчет с полученного значения?

    @alexalexes
    LaMass.
    1) На сервере считаете, какое число отдать пользователю для первой загрузки страницы, с учетом суточной экстраполяции + случайное значение. Отдаете пользователю это число, запоминаете в сессии PHP, что вы отдали и в какое время. Если в сессии есть какое-то значение, и оно от текущих суток, то досчитываете у него дельту и перезаписываете в сессию, отдаете новое значение пользователю. Если сутки изменились, то пересчитываете с нулевой точки и сохраняете в сессию.
    2) На клиенте отображаете текущее значение, и через setInterval и ajax запрашиваете на сервере, какое следующее число показать. На сервере считаете значение по экстраполяции по дельте времени от текущего времени и сохраненного в сессии, сохраняете новое значение счетчика и новое время в сессии. Отдаете клиенту новое значение.
    Ответ написан
    Комментировать
  • Выбор меню. Оставить фокус при загразки другой html?

    @alexalexes
    Вариант 1, решение на коленке, которое нужно здесь и сейчас.
    Написать костыль на JS в виде функции, которая возьмет подстроку из текущего url и произведет поиск нужной ссылки в меню с таким же href атрибутом, и поставит найденному html элементу класс активного элемента (или контейнеру ссылки - li элементу). Не забудьте прогуляться до первого уровня меню и тоже расставить классы активного элемента, если у вас меню многоуровневое.

    Вариант 2, как должно быть.
    У вас во входном скрипте index.php должен быть реализован примитивный роутинг url.
    Благодаря роутеру для каждой страницы вы точно можете получить путь из компонентов адреса.
    Например, site.com/page1/subpage2.
    От роутера вы легко можете получить путь к странице, хотя бы в таком виде:
    $page_path = ['page1', 'subpage2'];
    Также меню должно формироваться динамически, из какой-то сохраненной структуры, пусть структура будет статичной.

    $site_menu =
    [
       'page1' =>
       [
          'title' => 'Страница 1', 
          'child' => 
          [
             'subpage2' => ['title' => 'Субстраница 2', 'child' => []]
          ]
      ],
      'page2' =>
       [
          'title' => 'Страница 2', 
          'child' => []
      ],
    ];

    Примерная функция для формирования меню:
    // рекурсивная функция для получения сверстанного меню из структуры
    function get_main_menu(
       $curr_menu, //часть меню текущего уровня
       $level, // номер текущего уровня
       $menu_path, // путь к текущему уровню меню
       &$page_path // путь к текущей странице 
    )
    {  
      $out = '';
      if(count($curr_menu) > 0)
      {
        $out .= '<ul class="main-menu main-menu_level-'.$level.'">';
        foreach($curr_menu as $key_item => $menu_item)
        {
            $out .= '<li class="main-menu__item '
                     .($page_path[$level] == $key_item ? 'main-menu__curent' : '') // определяем текущий пункт меню
                   .'"><a href="'.$menu_path.'/'.$key_item.'">'.$menu_item['title'].'</a>';
            get_main_menu($curr_menu['child'], $level + 1, $menu_path.'/'.$key_item, $page_path); // рекурсивный вызов функции для прорисовки следующего уровня
            $out .= '</li>';
        }
        $out .= '</ul>';
      }
      return $out;
    }
     // получаем html-фрагмент меню по структуре
     $out_site_menu = get_main_menu($site_menu, 0, '', $page_path);
    Ответ написан
    1 комментарий
  • Как сделать редирект с подстановкой на php?

    @alexalexes
    Вы используете PHP сервер, а пути в url ведут к статичным html, а не на index.php.
    Допустим, по index.html сервер выполняет некий скрипт в index.php (допустим, вы настроили htaccess).
    То в этом скрипте все компоненты адреса можно получить через $_SERVER и отредиректить, куда надо:
    $protocol = $_SERVER['HTTPS'] == 'on' ? 'https' : 'http';
    $host = $_SERVER['HTTP_HOST'];
    $path = $_SERVER['SCRIPT_NAME']; 
    /****/
    // Что-то сделать с $protocol, $host, $path а может что-то еще забрать из $_GET, $_POST, $_FILES....
    /****/
    header('location: '.$protocol.'://'.$host.$path);
    Ответ написан
  • Как объединись значения из двух массивов в один?

    @alexalexes
    Типичная ситуация преобразовать плоский массив, полученный из запроса, в более объемный вложенный массив:
    $rows = /* тут выполняется запрос для получения данных */;
    $out_data = []; // массив выходных данных
    foreach($rows as $row)
    {
      $order = &$out_data[$row['order_id']]; // ссылка на элемент массива заказа
      $order['order_id'] = $row['order_id'];
      $order['firstname'] = $row['firstname'];
      $order['lastname'] = $row['lastname'];
      $order['telephone'] = $row['telephone'];
      if(!isset($order['products'])) $order['products'] = []; // этот if  нужен, если обязательно наличие ключа products с пустым массивом, если в выборке возможны пустые реквизиты продукта.
      if(!is_null($row['product_id']))
      { 
        $product = &$order['products'][$row['product_id']]; // делаем ссылку на элемент массива products с уникальным ключом product_id
        $product['product_id'] = $row['product_id'];
        $product['sku'] = $row['sku'];
        $product['quantity'] = $row['quantity'];
        // ... таким же способом можно делать более глубокие ссылки в product, если в этом элементе понадобится массив данных
        unset($product); // уничтожайте ссылку в конце цикла, иначе не сможете переиспользовать переменную $product за циклом.
      }
      unset($order);
    }
    Ответ написан
  • Как установить лимит на количество сканируемых файлов?

    @alexalexes
    Если в общих чертах рассказать, то вам нужно сделать такие шаги:
    1. Переписать функцию из рекурсивной формы в стековую форму. То есть, вместо того, чтобы пользоваться стеком вызова функций и помещать туда входные параметры вызова (в данном случае, $dir), вам нужно самим на основе массива создать стек для хранения параметров, чтобы реализовать хранение контекста текущей директории.
    После того, как вы организуете стек, вы легко можете прерывать функцию в любом месте и сохранять состояние стека в свойстве класса.
    2. Сохраняйте дескриптор $handle в свойстве класса и очищайте его, когда полностью пройдете по текущей директории или когда полностью закончите сканирование. Это также позволит прерывать функцию в любом месте.
    3. Чтобы сканировать по 100 файлов, делайте локальный счетчик внутри функции и просто выходите из функции, когда достигли макс. значения.
    4. Имея 1, 2 и 3, при очередном вызове функции сначала проверяете можно ли воспользоваться дескриптором $handle для чтения очередного файла, если нет, то попытаться вытащить следующий элемент из стека директорий, освежив дескриптор $handle.
    Если у вас удалось получить рабочий $handle, то сканирование продолжится.
    Когда сканирование находит очередной каталог, то его нужно положить в стек. Если переключаться на сканирование найденного каталога сразу, то у вас будет работать метод сканирования в глубину, если переключаться на новый каталог после того, как закончите сканирование текущего, то сканирование будет работать в ширину.
    ЗЫ: чтобы запустить функцию сначала, нужно положить в стек элемент с корневым каталогом.
    ЗЫЫ: В стеке удобнее будет хранить дескрипторы а не строковые пути, по ним удобно работать функцией readdir, если у вас будет поиск в глубину.
    Ответ написан
  • Как выбрать много пользователей через чекбоксы и выполнить sql запрос?

    @alexalexes
    Оборачиваете html-таблицу в форму, с кнопочкой сабмита. Когда отметили нужное, пользователь должен засабмитить форму. В форме нужно указать метод передачи GET или POST и адрес, где будет располагаться серверный скрипт обработки формы.
    В скрипте примерно такой код:
    <?php
    // считаем, что данные пришли по POST-у
    if(isset($_POST['submit'])) // проверяем, что приехали данные формы по submit, в кнопке сабмита атрибут name должен иметь значение submit
    {
       $inserted_user_count = 0;
       if(isset($_POST['selected_users'])) // присутствуют отмеченные пользователи
       {
          $pdo = new PDO(параметры подключения к базе);
          foreach($_POST['selected_users'] as $selected_user_id)
          {
            $stmt = $pdo->prepare('insert into ваша таблица (атрибуты таблицы) values (значения атрибутов таблицы, кроме user_id, :user_id)');
            $stmt->bindParam(':user_id', $selected_user_id, PDO::PARAM_INT);
            // еще байндим какие-то параметры у запроса, если есть плейсхолдеры, кроме :user_id.
            $stmt->execute(); // наконец, выполняем запрос
            $pdo->commit(); // фиксируем изменения в базе данных, если у вас соединение открыто не в режиме автокамита
            $inserted_user_count++;
          }
          $pdo = null; // закрываем соединение с базой
       }
       echo 'Обработано пользователей: '.$inserted_user_count;
    }
    ?>
    Ответ написан
    Комментировать
  • Как обрабатывать файл полученный пост запросом правильно?

    @alexalexes
    Именно так, как вы описали.
    Вообще, если вы используете нативные возможности серверного окружения для приема, передачи, чтения, записи данных по средством файлов, то вы должны морально готовы написать код так, чтобы минимальными ресурсами оперативной памяти (десятки мегабайт) перерабатывать объем данных (сотни мегабайт, гигабайты), расположенный в файлах, кратно превышаемый объем этой оперативной памяти, выделенной для выполнения скрипта.
    Поэтому, читать файлы вам в любом случае построчно (еще правильнее - поблочно, с ограничением макс. длины блока), и при обработки блока постоянно вспоминать, а сколько оперативной памяти кушается при получении данных из файла (делать отладку с профилированием памяти), передачи их в функции и методы обработки, до записи результата. Также научитесь вовремя очищать тяжеловесные переменные (внезапно unset окажется не так уж бесполезен).
    Ответ написан
    Комментировать
  • Как добавить два одинаковых скрипта в один файл?

    @alexalexes
    Все просто. Принцип переиспользования кода: если бизнес-логика вынуждает дублировать часть кода со слегка другими параметрами, то эта часть кода - отдельная функция (или метод), а изменяемые параметры и результат выполнения кода - это ее входные и выходные параметры.
    function file_session_write($base, $deltaLastTime)
    {
     $id = session_id();
     //текущее время
     $CurrentTime = time();
     //через какое время сессии удаляются
     $LastTime = time() - $deltaLastTime;
     $file = file($base);
     $k = 0;
     for ($i = 0; $i < sizeof($file); $i++) {
      $line = explode("|", $file[$i]);
       if ($line[1] > $LastTime) {
       $ResFile[$k] = $file[$i];
       $k++;
      }
     }
    
     for ($i = 0; $i<sizeof($ResFile); $i++) {
      $line = explode("|", $ResFile[$i]);
      if ($line[0]==$id) {
          $line[1] = trim($CurrentTime)."\n";
          $is_sid_in_file = 1;
      }
      $line = implode("|", $line); $ResFile[$i] = $line;
     }
    
     $fp = fopen($base, "w");
     for ($i = 0; $i<sizeof($ResFile); $i++) { fputs($fp, $ResFile[$i]); }
     fclose($fp);
    
     if (!$is_sid_in_file) {
      $fp = fopen($base, "a-");
      $line = $id."|".$CurrentTime."\n";
      fputs($fp, $line);
      fclose($fp);
     }
      return sizeof(file($base));
    }
    session_start();
    // а тут просто вызываем функцию с какими угодно параметрами, сколько угодно раз
    $result1 = file_session_write( "session1.txt", 30);
    $result2 = file_session_write( "session2.txt", 86400);
    echo 'res1='.$result1.'; res2='.$result2;
    Ответ написан
  • Как узнать название вложенного массива?

    @alexalexes
    Вы пользуетесь неполной версией foreach.
    foreach($arr as $value)
    {
      echo $value;
    }

    Нужно та, что ключи перебирает.
    foreach($arr as $key => $value)
    {
      echo $key;
    }
    Ответ написан
    Комментировать