Показаны сообщения с ярлыком PHP. Показать все сообщения
Показаны сообщения с ярлыком PHP. Показать все сообщения

пятница, 25 апреля 2025 г.

Экспорт из PHP в CSV большого кол-во данных

В PHP существует удобный инструмент php://output, который, подобно конструкциям print и echo, позволяет выводить данные в выходной буфер, не загружая память сервера. Как его использовать? Прежде чем привести пример, отмечу, что в ООП экспорт данных (например, сохранение) должен выполняться в контроллере, а бизнес-логика (выборка, агрегация и т.д.) — в модели. Ниже представлен простой пример без использования ООП:

// Отключаем кэширование
header('Cache-Control: no-cache, no-store, must-revalidate');
header('Expires: 0');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');

// Устанавливаем заголовки для CSV
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename="export.csv"');
header('Content-Transfer-Encoding: binary');

// Пример получения данных (заменить на реальную выборку из БД)
$list = [
    ['_id' => 1, 'date' => time(), 'user' => 'John'],
    ['_id' => 2, 'date' => time(), 'user' => 'Jane'],
    // ... другие данные
];

// Заголовки для CSV
$titles = ['ID', 'Date', 'User'];

// Открываем поток php://output
$df = fopen('php://output', 'w');
if ($df === false) {
    die('Ошибка открытия потока php://output');
}

// Записываем заголовки
fputcsv($df, $titles);

// Записываем данные
foreach ($list as $row) {
    // Проверяем, не прервано ли соединение
    if (connection_aborted()) {
        fclose($df);
        die('Соединение с клиентом прервано');
    }

    fputcsv($df, [
        $row['_id'],
        date('Y-m-d H:i:s', $row['date']),
        $row['user'],
        // Добавить другие поля, если нужно
    ]);

    // Очищаем буфер для экономии памяти
    flush();
}

// Закрываем поток
fclose($df);

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

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

В чем еще проблема? Несмотря на экономию серверной памяти, у метода есть недостаток: во время потоковой передачи данных в файл скрипт продолжает выполняться. Однако время выполнения скрипта ограничено (обычно около 15 секунд, если не изменять настройки). Если сохранение, например, 50 тысяч записей занимает больше 15 секунд, возникнет ошибка fatal error из-за превышения времени выполнения.

Источник

вторник, 7 мая 2019 г.

Подсветка кода для blogger

Пересмотрел кучу вариантов для подсветки кода в blogger, единственное на данный момент рабочее решение это https://highlightjs.org

О том как его добавить в блог читаем здесь - https://81code.blogspot.com/2016/04/syntax-highlighter-blogger.html

Перед тем как вставить код, его нужно обработать например в HTML Escape
Еще для себя добавил плагин показа номеров строк - https://github.com/wcoder/highlightjs-line-numbers.js/

понедельник, 6 мая 2019 г.

Находим в тексте ссылки youtube и конвертим их в embed видео

Код:

function convertYoutube($string) {
    return preg_replace(
        "/\s*[a-zA-Z\/\/:\.]*youtu(be.com\/watch\?v=|.be\/)([a-zA-Z0-9\-_]+)([a-zA-Z0-9\/\*\-\_\?\&\;\%\=\.]*)/i",
        "<iframe src=\"//www.youtube.com/embed/$2\" allowfullscreen></iframe>",
        $string
    );
}

Источник: stackoverflow.com

вторник, 30 мая 2017 г.

yii2 полезные мелочи

Как в yii2 проверить isNewRecord в afterSave()

Теперь алгоритм проверки после сохранения такой:
app\models\Model
public function afterSave($insert, $changedAttributes)
    {
        if ($insert) {
                // Да это новая запись (insert)
        } else {
                // Нет, старая (update)
        }
        parent::afterSave($insert, $changedAttributes);
}

 

Не находит action из контроллера Not Found (#404)

В yii2 есть особенность с именование action в отличие от yii1:
в контроллере создаем action
public function actionLastNews()
{
////
}
при стандартных rules этот экшн будет доступен по адресу: /last-news
Эта мелочь может попортить немало нервов.

Подключение javascript в yii2

Inline js

Во view можно подключить произвольный javascript код:
$var = 123;
//начало многосточной строки, можно использовать любые кавычки
$script = <<< JS
    function foo() {
        return $var; //можно использовать переменные
    }
JS;
//маркер конца строки, обязательно сразу, без пробелов и табуляции
$this->registerJs($script, yii\web\View::POS_READY);
получим сразу перед закрытием body:
<script type="text/javascript">
jQuery(document).ready(function () {
    function foo() {
        return 123;
    }
});</script>
</body>
другие варианты места подключения скрипта: (документация)
  • POS_HEAD
  • POS_BEGIN: после тэга
  • POS_END: перед тэгом
  • POS_LOAD: оборачивается в jQuery(window).load(). Note that by using this position, the method will automatically register the jQuery js file.
  • POS_READY: оборачивается вjQuery(document).ready(). This is the default value. Note that by using this position, the method will automatically register the jQuery js file.
  • js-файл

    $this->registerJsFile('url/to/file.js',  ['position' => yii\web\View::POS_END]);
     
    Скопировано отсюда 

    среда, 28 декабря 2016 г.

    5 лет независимости

    28 декабря 2016 года стукнуло 5 лет как вышел наш первый релиз CMS Open Real Estate. С тех пор много чего было интересного и не очень. Трудно взбираться в гору, особенно в начале пути. Но мы смогли добиться относительной стабильности. Недавно я поймал себя на мысли, что фраза из сказки про Алису -

    Нужно бежать со всех ног, чтобы только оставаться на месте, а чтобы куда-то попасть, надо бежать как минимум вдвое быстрее!

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

    О становлении нашей компании с картинками можно почитать здесь.

    четверг, 25 августа 2016 г.

    Получаем координаты районов с помощью API OSM

    Итак, всё до безобразия просто, делаем запрос:
    http://nominatim.openstreetmap.org/search?format=json&q=%D0%9A%D1%80%D0%BE%D0%BD%D1%88%D1%82%D0%B0%D0%B4%D1%82%D1%81%D0%BA%D0%B8%D0%B9%20%D1%80%D0%B0%D0%B9%D0%BE%D0%BD,%20%D0%A1%D0%B0%D0%BD%D0%BA%D1%82-%D0%9F%D0%B5%D1%82%D0%B5%D1%80%D0%B1%D1%83%D1%80%D0%B3&polygon_geojson=1
    Всё  Получаем в ответ geojson (массив с географическими координатами) и делаем с ним что хотим.
    Например, я решил обработать его в несколько ином виде, чтобы скармливать Яндекс.Картам. Для этого я накидал простеньку функцию на PHP:
    function areaCoordsParser($search)
    {
        $query = http_build_query([
            'format' => 'json',
            'q' => $search,
            'polygon_geojson' => 1,
        ]);
        $url = "http://nominatim.openstreetmap.org/search?$query";
        $response = json_decode(file_get_contents($url), true);
        $result = [];
        if ($response[0]['geojson']['type'] === 'MultiPolygon') {
            $coords = $response[0]['geojson']['coordinates'];
            foreach ($coords as $coord) {
                $temp = [];
                foreach ($coord[0] as $item) {
                    $temp[] = array_reverse($item);
                }
                $result[] = $temp;
            }
        } elseif ($response[0]['geojson']['type'] === 'Polygon') {
            $coords = $response[0]['geojson']['coordinates'][0];
            foreach ($coords as $coord) {
                $result[] = array_reverse($coord);
            }
        }
        return $result;
    }
    echo json_encode(areaCoordsParser('Адмиралтейский район, Санкт-Петербург'));
    Источник - http://zabolotskikh.com/tips/kak-poluchit-koordinaty-rayonov/

    вторник, 31 мая 2011 г.

    Абстрактная фабрика - (Abstract Factory)

    Список паттернов
    Код - пример #1
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    <?php
    /*
    
    Абстрактная фабрика - (Abstract Factory)
    
    Фабрика должна возвращать объекты. Но так как она абстрактная, то изначально нужно
    описать абстрактный класс фабрики, и абстрактные объекты которые она будет производить. 
    
    Дале мы описываем реализации классов фабрик на основе абстрактной фабрики и реализации класса объектов
    которые она производит. Тем самым у нас есть различные варианты фабрик и объектов с одинковыми
    интерфейсами, что может быть удобно.
    
    Далее привожу код. Есть абстрактная фабрика машин. Абстрактный класс машин. Создаем классы фабрики
    "ford" и "vaz" и классы ford_machine и vaz_machine. Фабрики будут производить объект "машины", но
    свойство "начинака" этих "машин" будет отличаться, прям как в реальной жизни.
    
    */
    
    abstract class abstract_machine_factory {
        function generate_sedan() {
            return new machine('sedan');
        }
        
        function generate_universal() {
            return new machine('universal');    
        }
        
        function generate_hatchback() {
            return new machine('hatchback');    
        }
    }
    
    abstract class abstract_machine {
        protected $_param;
    
        function __construct($type = 'sedan') {
            $this->_param = array();
            $this->_param['type'] = $type;
        }    
        
        function run() {
            echo 'brrrrrrrrrrrrrr ...';
        }
        
        function get_all_param() {
            return $this->_param;
        }
    }
    
    class vaz_machine extends abstract_machine {
        function __construct($type = 'sedan') {
            parent::__construct($type);
    
            $this->_param['firm'] = 'vaz';
        }
    
        function run() {
            echo 'tr tr pr tr tr pr ...';
        }
    }
    
    class vaz_factory extends abstract_machine_factory {
        function generate_sedan() {
            return new vaz_machine('vedro');
        }
        
        function generate_universal() {
            return new vaz_machine('taz');    
        }
        
        function generate_hatchback() {
            return new vaz_machine('korito');    
        }    
    }
    
    class ford_machine extends abstract_machine {
        function __construct($type = 'sedan') {
            parent::__construct($type);
            
            $this->_param['firm'] = 'ford';
        }
    
        function run() {
            echo 'rrrrrrrrrrrrrrrrr ...';
        }
    }
    
    class ford_factory extends abstract_machine_factory {
        function generate_sedan() {
            return new ford_machine('sedan', 'ford');
        }
        
        function generate_universal() {
            return new ford_machine('universal');    
        }
        
        function generate_hatchback() {
            return new ford_machine('hatchback');    
        }    
    }
    
    /* Фабрика ford_factory производит машины */
    $ford_factory = new ford_factory();
    $ford_machine = $ford_factory->generate_sedan();
    
    deb($ford_machine->get_all_param());
    deb($ford_machine->run());
    
    /* Фабрика vaz_factory производит машины, функции одинаковые но результат (объекты) разные */
    $vaz_factory = new vaz_factory();
    $vaz_machine = $vaz_factory->generate_sedan();
    
    deb($vaz_machine->get_all_param());
    deb($vaz_machine->run());
    
    /* В результате мы видим на экране:
    
    Array
    (
        [type] => sedan
        [firm] => ford
    )
    
    rrrrrrrrrrrrrrrrr ...
    
    Array
    (
        [type] => vedro
        [firm] => vaz
    )
    
    tr tr pr tr tr pr ...
    
    */
    
    function deb($mVar) {
        echo("<PRE>");
        print_r($mVar);
        echo("</PRE>");
    }
    
    

    Список паттернов

    Паттерны проектирования с примерами PHP

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


    Порождающие паттерны.


    Эта одна из категорий на которые разбивают шаблоны проектирования. В свою очередь эту категорию делят еще на два типа — паттерны порождающие объекты и паттерны порождающие классы. Первые создаются с помощью другого объекта, вторые с помощью наследования изменяют класс создаваемого объекта.
    Основная идея порождающих паттернов заключается в том, что инстанцирование объектов происходит «за кадром», они скрывают в себе какие именно классы используются в приложении и детали их реализации, оставляя только интерфейсы к ним. По-идее это позволяет собрать полностью рабочее приложение из различных заготовленных заранее объектов, но по своему опыту скажу, что это практически невозможно без использования других типов шаблонов.

    Их всего 5:
    1. Абстрактная фабрика (Abstract Factory)
    2. Одиночка (Singleton)
    3. Прототип (Prototype)
    4. Строитель (Builder)
    5. Фабричный метод (Factory Method)


    Структурные паттерны.


    Здесь также есть два типа — паттерны уровня класса и паттерны уровня объекта. Самым ярким примером первых, на мой взгляд является «Адаптер». Общий смысл его в том, что если вдруг у нас есть класс и его интерфейсы не совместимы с другими библиотеками в нашей системе, то что бы разрешить этот конфликт, мы не изменяем код этого класса, а пишем для него адаптер. Очень часто этот паттерн применяется при написании библиотек, которые позволяют работать с различными СУБД. Паттерны уровня объекта позволяют достичь большей гибкости в приложения во время его выполнения. Наиболее популярный из них - «Декоратор».

    Всего 7:
    1. Адаптер (Adapter)
    2. Декоратор (Decorator)
    3. Заместитель (Proxy)
    4. Компоновщик (Composite)
    5. Мост (Bridge)
    6. Приспособленец (Flyweight)
    7. Фасад (Facade)


    Паттерны поведения.


    Основная идея паттернов этого типа — взаимодействие объектов и классов между собой. Но они также делятся на два уровня — паттерны поведения уровня класса и паттерны поведения уровня объекта. Здесь самое сложное это добиться наименьшей степени связанности компонентов системы друг с другом, потому что почти все объекты должны знать о существовании других и нести в себе эту информацию. Отсюда и появились такие сложные паттерны как «Посредник» и «Цепочка обязанностей».

    Их 11:
    1. Интерпретатор (Interpreter)
    2. Итератор (Iterator)
    3. Команда (Command)
    4. Наблюдатель (Observer)
    5. Посетитель (Visitor)
    6. Посредник (Mediator)
    7. Состояние (State)
    8. Стратегия (Strategy)
    9. Хранитель (Memento)
    10. Цепочка обязанностей (Chain of Responsibility)
    11. Шаблонный метод (Template Method)


    скопипастил

    четверг, 21 апреля 2011 г.

    Определение IP пользователя PHP

    function ip() {
        if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
            $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
        } elseif (isset($_SERVER['HTTP_CLIENT_IP'])) {
            $ip = $_SERVER['HTTP_CLIENT_IP'];
        } else {
            $ip = $_SERVER['REMOTE_ADDR'];
        }
        return $ip;
    }
    

    суббота, 5 февраля 2011 г.

    Клиентская и серверная валидация

    Одна из наиболее частых задач в web-разработке - создание форм и проверка их на корректность вводимых данных. Для того чтобы это все было более юзабильно, есть специальный jQuery Validation Plugin. Этот плагин позволяет на стороне клиента, проверять форму на корректность вводимых данных, соответственно не требуется перезагрузка страницы.

    Чтобы облегчить создание форм в web-приложениях, существуют различные библиотеки. Одна из них HTML_QuickForm2 и ее доработка jQuickForm которая должна была подружить, этот построитель форм с jQuery Validation Plugin. Вышло на мой взгляд не плохо, но слишком наворочено. К тому же автор давно не развивал это дополнение, последний раз когда я скачивал этот пакет, не работала клиентская валидация, а ведь изначально именно для этого и был разработанн этот пакет.

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

    У всех этих "помошников" построителей форм, есть минусы - 1. Необходимо разбиратся с интерфейсами классов, как правило, сделано удобно, разобраться можно быстро 2. Сложности кастомизации, изменения дизайна форм 3. Все эти надстройки жрут ресурсы

    После размышлений над этим, я создал небольшой класс, который занимается только валидацией, правила задаются аналогично jQuery Validation Plugin. Объект этого класса создает необходимый код JS для валидации на стороне клиента (если нужно) и также проверяет формы на стороне сервера по тем же правилам. Привожу пример -

    
    <?php
    header("Content-Type: text/html; charset=utf-8");
    require 'valid/Valid.php';
    require 'valid/ValidLang.php';
    
    $oValid = new Valid($l);
    $oValid->addRule('login', 'required');
    $oValid->addRule('login', 'minlength', 5);
    $oValid->addRule('pass', 'required');
    $oValid->addRule('pass', 'minlength', 5);
    $oValid->addRule('re_pass', 'equalTo', 'pass');
    $oValid->addRule('email', 'required');
    $oValid->addRule('email', 'email');
    
    if (isset($_POST['login'])) {
       if ($oValid->check()) {
           // Здесь можно проверить дополнительно, на повторный логин и мыло например
           echo 'Валидация успешна';
           // Сохраняем данные, редиректим если надо
       }
    }
    ?>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
       <head>
           <title>Valid - mini validator</title>
           <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
         
           <link rel="STYLESHEET" type="text/css" href="css/eform.css">
           <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script>
           <script type="text/javascript">
                   !window.jQuery && document.write('<script src="js/jquery-1.4.3.min.js"><\/script>');
           </script>
           <script type="text/javascript" src="js/jquery.validate.pack.js"></script>
           <script type="text/javascript" src="js/jquery.form.js"></script>
       </head>
     
    <body>
    
    <form action="index.php" method="post" name="reg_form" id="reg_form" class="eForm">
       <fieldset>
           <legend><?php echo $l['index']['registration']; ?></legend>
           <p>
               <label for="login"><?php echo $l['index']['login']; ?></label>
               <input type="text" id="login" name="login" value="<?php echo $oValid->getReq('login');?>" />
               <?php echo $oValid->getErr('login');?>
           </p>
           <p>
               <label for="pass"><?php echo $l['index']['pass']; ?></label>
               <input type="password" id="pass" name="pass" value="" />
               <?php echo $oValid->getErr('pass');?>
           </p>
           <p>
               <label for="re_pass"><?php echo $l['index']['re_pass']; ?></label>
               <input type="password" id="re_pass" name="re_pass" value="" />
               <?php echo $oValid->getErr('re_pass');?>
           </p>
           <p>
               <label for="email"><?php echo $l['index']['email']; ?></label>
               <input type="text" id="email" name="email" value="<?php echo $oValid->getReq('email');?>" />
               <?php echo $oValid->getErr('email');?>
           </p>
           <p>
               <input type="submit" value="<?php echo $l['index']['registration']; ?>" class="noresize submit"/>
           </p>
       </fieldset>
    </form>
    
    <?php echo $oValid->getJS('reg_form'); ?>
    
    </body>
    </html>
    
    
    Пример реализации можно посмотреть в моем mini MVC framework, там уже реализована регистрация, авторизация - mFram

    вторник, 1 февраля 2011 г.

    Логирование ошибок в файл Denwer

    Как оказалось Denwer не логирует php ошибки в файл, а штука очень даже нужная особенно на фоне борьбы с ошибками. Чтобы он начал логировать, нужно вставить вот такой фрагмент кода в файл .htaccess :
    php_value error_reporting E_ALL
    php_value display_errors Off
    php_value display_startup_errors Off
    php_value log_errors On
    php_value log_errors_max_len 1024
    php_value ignore_repeated_errors Off
    php_value ignore_repeated_source Off
    php_value report_memleaks On
    php_value track_errors Off
    php_value html_errors Off
    php_value error_log "error.log"

    вторник, 25 января 2011 г.

    Парсим курс валют

    Код - пример #1
    1
    2
    3
    4
    5
    6
    7
    
    $url = 'http://www.cbr.ru/scripts/XML_daily.asp?date_req='.date("d/m/Y");
    $buf = file_get_contents($url);
    if($buf) {
     $xmldoc = new SimpleXMLElement($buf);
     $result = $xmldoc->Xpath("//Valute[@ID='R01239']"); //R01239 код евро
     echo $result[0]->Value;
    }
    Скопипастил