Ответы пользователя по тегу PHP
  • Можно ли как либо защитить 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;
    }
    Ответ написан
    Комментировать
  • Ошибка при JSON.parse как исправить?

    @alexalexes
    Можно сделать из буханки хлеба троллейбус, но зачем?
    var dataJSONArray = JSON.parse('<?php echo str_replace( "\'", "\\'",json_encode($u,JSON_UNESCAPED_UNICODE)); ?>');
    Ответ написан
    Комментировать
  • Как получить "хеш"/сравнить изображение?

    @alexalexes
    Для ведения новостей прежде всего нужно определить порядок, как создавать каталоги для хранения сопутствующего контента для людей, кто ведет их. Если плагин галереи не берет на себя обязанность автоматически создавать каталоги под свои нужды и не скрывает это от контент-менеджера, то контент-менеджер (человек) тупо складывает картинки в один каталог.
    На моей практике я делаю так.
    Под новости создаю каталог news, в каталоге на каждый год создаю каталог года - 2023.
    Внутри каталога года создается каталог конкретной новости, который создается менеджером для новости, если требуется положить дополнительный контент. Обычно, имя у него такое: YYYY_MM_DD_NN, где YYYY - год, MM - месяц, DD - день, NN - порядковое число новости в один день.
    Для повторяющегося контента можно задать каталог по умолчанию в news, например default, и складывать туда часто используемые изображения, заглушки и т.д.
    И самое, главное, чтобы эту практику поддерживали менеджеры, тогда проблем с дублированием не будет, и не будет бардака в новостях.
    Ответ написан
  • Где здесь ошибка?

    @alexalexes
    Палим учетные данные окружения сервера.
    $conn = new mysqli("localhost", "y96360rs_a", "xR&O&&37", "y96360rs_a");

    То, что вы в вопросе показали пример запроса с параметрами - он выполнен с помощью склейки строк - так делать нельзя. Подготовленные запросы пишутся так:
    $sql = "UPDATE `admins` SET `login` = ?, `pass` = ?, `name` = ?, `role` = ? WHERE `id` = ?";
    $stmt = $conn->prepare($sql);
    $stmt->bind_param('ssssi', $login, $pass, $name, $role, $id);

    Почувствуйте разницу.
    $id = $conn->insert_id;
    Зачем оно после запроса обновления, вы же знаете id изначально?
    Ответ написан
    Комментировать
  • Как лучше запрятать важные данные в коде?

    @alexalexes
    Свою клиентскую часть платежной системы делаешь как отдельный микросервис со своим локальным API и используешь на более подготовленном серверном окружении с точки зрения безопасности.
    Ответ написан
    Комментировать
  • Почему текстовый файл (.txt) превращается в бинарный?

    @alexalexes
    1. Какой-то другой скрипт переписал файл.
    2. Найти этот скрипт. Или заменить пути сохранения файлов, если лень.
    3. Взять из резервной копии (только не говорите, что у вас их нет).
    Ответ написан
    8 комментариев
  • Как показать определенное количество символов у ссылки а остальные скрыть?

    @alexalexes
    Проще со стороны формирующего скрипта подрезать лишнее внутри тега a.
    <?php echo mb_strlen($t_url) > 10 ? mb_substr($t_url, 0, 10).'...' : $t_url; ?>
    Ответ написан
    Комментировать
  • Как работает поиск по таблице в PhpMyAdmin?

    @alexalexes
    Откройте любую картинку взаимодействия:
    клиент <-> сервер приложений <-> сервер СУБД <-> физическое хранилище.
    И ответ будет просто иллюстрацией, как запрос от пользователя будет идти от клиента к хранилищу и обратно:

    Оболочка PhpMyAdmin формирует текст sql запроса выборки данных, драйвер расширения PHP для конкретной СУБД передает запрос в запущенный процесс СУБД mySQL. СУБД парсит запрос, строит план выполнения запроса, выполняет его, передает выборку данных обратно драйверу расширения, PHP отдает ответ оболочке PhpMyAdmin, или сам рисует эту оболочку голым HTML.
    Ответ написан
    Комментировать