Управляемая загрузка файлов на PHP и Nginx с использованием Accel-Redirect

Предположим, вам нужно ограничить возможность загрузки файлов и у вас PHP приложение. Файлы же могут находиться на удаленном или локальном по отношению к сайту хосте.
Есть пара вариантов как это сделать:

  1. Загружать файлы средствами PHP в TMP, проверять может ли пользователь их скачать или нет и отдавать или не отдавать файл
  2. Воспользоваться заголовком x-accel-redirect доступном в Nginx.
Continue reading

Как задавать права доступа в Symfony используя базу данных (Voters used database)

С тех пор, как вся конфигурация Symfony кешируется с контейнером для лучшей производительности , мы по очевидным причинам не должны использовать базу данных что бы где-то «напечатать» новую конфигурацию, нам нужно что-то умнее.

Использование Symfony Voters

Symfony использует Voters что бы определить доступ к URL и другим ресурсам. Множество voters которые входят в комплект поставки вместе с Symfony security  которые используют конфигурацию в security.access_control что бы определить нужно ли давать права на запрос или нет.

Continue reading

Деревья в PHP + Twig 2.0

Предположим, есть задачка, вывести дерево.

Под рукой PHP, а как view — Twig.

Пусть структура данных на backend будет такой:

$tree = [

            [
                'name' => 'foo',
                'children' => [
                    [
                        'name' => 'bar',
                        'children' => [
                            [
                                'name' => 'baz',
                                'children' => [

                                ],
                            ],

                            [
                                'name' => 'baz',
                                'children' => [

                                ],
                            ],


                        ]
                    ]
                ]
            ]

        ];

Тогда простроить дерево можно так:

{% macro makeTree(node) %}
    {% import _self as self %}
    
  • {{ node.name }} {% if node.children|length %}
      {% for child in node.children %} {{ self.makeTree(child) }} {% endfor %}
    {% endif %}
  • {% endmacro %} {% from _self import makeTree %} {% if tree %}
      {% for node in tree %} {{ makeTree(node) }} {% endfor %}
    {% endif %}

    Получится вложенный список из ul и li.

    Как определить квартал из даты в PHP

    Функции для работы с датой и временем, которые поставляются с PHP прекрасны для форматирования дат, однако отсутствует простой способ определить квартал для timestamp или объекта DateTime.

    Вот тут маленькая функция, которая умеет возвращать квартал из DateTime:

    /**
     * Return the quarter for a timestamp.
     * @returns integer
     */
    function quarter(\DateTime $dateTime){
       return (int) ceil($dateTime->format('n') / 3);
    }
    

    Человекочитаемый размер файла в PHP

    Маленькая функция для преобразования размера  в байтах в человекочитаемый вид:

    <?php
    function human_filesize($bytes, $decimals = 2) {
        $size = array('B','kB','MB','GB','TB','PB','EB','ZB','YB');
        $factor = (int) floor((strlen($bytes) - 1) / 3);
        return sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)) . @$size[$factor];
    }
    

    Использование

    <?php
    echo human_filesize(filesize('example.zip'));

    Источник

    Миграция пользователей на безопасный алгоритм хеширования в Symfony

    Ваше приложение может использовать старый, небезопасный алгоритм хеширования для хранения пароля, такой как MD5 (без использования соли)

    Эта статья объясняет как преобразовать уже имеющиеся пароли, зашифрованные уязвимым алгоритмом в пароли зашифрованные с использованием безопасного метода хеширования (например с использованием Bcrypt )

    Что бы решить проблему, мы сделаем конвертацию на лету, когда пользователь успешно входит в систему. Будем использовать интерфейс EncoderAwareInterface

    login listener и использовать не очень хорошо известные параметры в security.yml.
    Continue reading

    ORDER BY RAND() in Doctrine without implement a new Doctrine function

    Предположим, что нам нужно выбрать N строк из базы данных и отсортировать их случайным образом. При этом у нас нет возможности (или желания) реализовывать функцию rand() в Doctrine. 

    В MySQL эта задача решается очень просто:

    SELECT column FROM table
    ORDER BY RAND()
    LIMIT 10

    Но если вы используете DQL (Doctrine Query Language) это будет не так просто. Следуя документации вы можете реализовать расширение для Doctrine и добавить инструкцию RAND в запросы, но мы не будем этого делать.

    Для нашего решения мы будем использовать конструкцию where IN и будем искать что-нибудь (в данном случае ID или другое поле с автоинкриметом, если ваша таблица не содержит первичного ключа с автоинкриментом, вы должны реализовывать RAND расширение для Doctrine) в соответствии с случайными числами полученными при помощи простой функции на php.

    В данном примере, таблица имеет поле с автоинкриментом, которое называется id (которая содержит в себе числовые значения), что бы получить случайные записи нам нужно для начала создать функцию, которая возвращает случайные числа в заданном диапазоне (начальное значение, максимальное значение и количество), например, такую как эта:

    function UniqueRandomNumbersWithinRange($min, $max, $quantity) {
    $numbers = range($min, $max);
    shuffle($numbers);
    return array_slice($numbers, 0, $quantity);
    }

    UniqueRandomNumbersWithinRange выдаст нам числа в заданном диапазоне, эти числа мы будем использовать что бы искать случайные строки в нашей таблице при помощи Doctrine, вот так:

    $em = $this->getDoctrine()->getManager();
    $repo = $em->getRepository('AppBundle:EntityName');
    $quantity = 5;
    $totalRowsTable = $repo->createQueryBuilder('a')->select('count(a.id)')->getQuery()->getSingleScalarResult();
    
    $randomIds = UniqueRandomNumbersWithinRange(1,$totalRowsTable,$quantity);
    
    $random_articles = $repo->createQueryBuilder('a')
    ->where('a.id IN (:ids)') // если у вас другое поле - поменяйте это
    ->setParameter('ids', $randomIds)
    ->setMaxResults(3)// Добавьте эту строку если вы хотите получить ограниченное количество записей (Если все IDs существуют вам будет нужно ограничение)
    ->getQuery()
    ->getResult();
    

    Эта статья является вольным переводом этой

    «405 method not allowed» IIS for Restful methods

    По-умолчанию в IIS запрещены методы, которые используется в Restful API, например DELETE, PUT и другие.

    Для того, что бы разрешить эти методы нужно:

    1. В диспетчере IIS открыть Сопоставления обработчиков
    2. Найти обработчик PHP, зайти в его настройки
    3. Ограничение запроса…
    4. Команды
    5. Прописать необходимые методы, например: GET,POST,PUT,DELETE, а также можно разрешить все.

    Flat array to nested in php

    Requirements = PHP 5.3

    function buildTree($flat, $pidKey, $idKey = null)
            {
                $grouped = array();
                foreach ($flat as $sub){
                    $grouped[$sub[$pidKey]][] = $sub;
                }
    
                $fnBuilder = function($siblings) use (&$fnBuilder, $grouped, $idKey) {
                    foreach ($siblings as $k => $sibling) {
                        $id = $sibling[$idKey];
                        if(isset($grouped[$id])) {
                            $sibling['children'] = $fnBuilder($grouped[$id]);
                        }
                        $siblings[$k] = $sibling;
                    }
    
                    return $siblings;
                };
    
                $tree = $fnBuilder($grouped[0]);
    
                return $tree;
            }
    

    Usage:

    $flat = array(
        array('id'=>100, 'parentID'=>0, 'name'=>'a'),
        array('id'=>101, 'parentID'=>100, 'name'=>'a'),
        array('id'=>102, 'parentID'=>101, 'name'=>'a'),
        array('id'=>103, 'parentID'=>101, 'name'=>'a'),
    );
    
    $tree = buildTree($flat, 'parentID', 'id');
    print_r($tree);
    

    Thanks! http://stackoverflow.com/a/27360654/1886270