Chulakov Dev
1.15K subscribers
140 photos
5 videos
205 links
Канал команды разработки Студии Олега Чулакова.

Советы по Frontend- и Backend-разработке web-сервисов, мобильных приложений, статьи и презентации от наших разработчиков, анонсы проектов и многое другое.

Обсудить проект @YuraAndreev
Download Telegram
Добро пожаловать на канал команды разработки группы Chulakov Digital.

Мы планируем размещать здесь советы и рекомендации по разработке web-сервисов, примеры и заметки по созданию анимации, внутристудийные статьи и презентации, анонсы наших Open Source и корпоративных проектов, будем (самую чуточку) показывать процесс работы, а также курьезы, которые в нем возникают.

Если кто-то забыл или (такого конечно быть не может) не знал о наших успехах:

Ежегодно Студия Олега Чулакова запускает десятки сайтов, систем и веб-сервисов, выпускает мобильные приложения, занимаемся поддержкой федеральных и международных клиентов, а также тестированием всего этого добра.

Мы запустили много проектов (весьма неплохих, надо сказать) и, сейчас, компания входит в Топ-2 дизайн-студий, Топ-8 ведущих производственных digital-агентств России и является самым награждаемым российским digital-агентством по версии Tagline.
О Frontend-стеке

Сейчас в основе Frontend-а большинства наших проектов лежит корпоративный boilerplate, включающий в себя:
— React, React Router
— Redux, Redux Form
— ES6, Babel
— Webpack, Gulp
— Stylus, PostCSS
— ESlint

Для небольших или промо-проектов используем сборку, которая работает на Gulp и инструментах вроде Babel, Stylus, PostCSS, CSSO и UglifyJS.

Кроме того, мы знатно разбираемся в анимациях (эта тема, наверняка, многим интересна), делаем 2D-анимации, игры и 3D-интерактив с помощью:
— Canvas 2D-context (например, фоны на silasveta.com)
— CreateJS (гляньте на болид bakucitycircuit.com, врум!)
— PixiJS (мини-игры на главной playkot.com)
— ThreeJS (крутая 3D-карта Азербайджана bakucitycircuit.com/en/azerbaijan)
Стрелочные функции в классах JavaScript

Если вы разрабатываете на React или просто «пишете» на ECMAScript 6 и часто пользуетесь классами, то вам наверняка приходится бороться за сохранность контекста при вызове функций.

По нашим наблюдениям, эту проблему, как правило, решают с помощью bind:

this.doSomething.bind(this)


Мало кто знает, что можно избавиться от «кучи» bind-ов:
Если подключить к проекту babel-плагин transform-class-properties, то станет возможным использование в классах стрелочных функций, которые не теряют контекст экземпляра класса:

 class Test extends Component { 
doSomething = () => {
this.setState({ done: true });
}
render() {
return <div onClick={this.doSomething}>Do it</div>
}
}


Кроме того, у плагина есть ещё несколько классных возможностей (например, установка дефолтных свойств экземпляра без конструктора) с которыми можно ознакомиться перейдя по прикрепленной ссылке.
Displacement Mapping

Если кому-нибудь вскружила голову карта Азербайджана на сайте Гран-при Формулы 1 в Баку (https://bakucitycircuit.com/en/azerbaijan) и интересно как мы сделали трехмерный рельеф — нам не жалко рассказать.

Начнем с того, что 3D-модели города Баку и гор Азербайджана у нас не было (печаль, что уж говорить).

Мы раздобыли спутниковые снимки и начали много думать над тем, как превратить это в 3D. Теплым (Ростов же) апрельским днем мы прочитали про технику под названием Displacement mapping, которая идеально подходит под задачу связанную с построением 3D-рельефа. Об этой заумной штуке даже на Википедии есть.

Суть достаточно проста — за счет изображения (имя ему Карта Смещений) выдавливаются точки в плоском (и не только) объекте — чем светлее точка на изображении, тем сильнее выдвигается это место на объекте. Круто, а?

Мы вам даже демо не поленились сделать:
https://dev.chulakov.ru/displacement-map/public/

Кроме того, нам повезло найти сервис https://terrain.party/, в котором можно получить Карту Смещений для любого участка на планете. Так что, как вы поняли, мы довольно быстро добились желаемого результата.

В завтрашней заметке покажем вам еще одно крутое демо и расскажем как наложить Карту Смещений на объект, чтобы получить 3D-рельеф.
Делаем это на ThreeJS

Для тех кому мало демки и хочется получить «рецепт», покажем как можно легко совместить объект с картой смещений.

Если вооружиться библиотекой Three.JS, то это совсем несложно, даже если объект не является плоскостью. Смотрите:
https://codepen.io/OlegChulakovStudio/pen/pWrBop?editors=0010
О Backend-стеке

При разработке сервисов мы делаем упор на обеспечение максимальной гибкости, расширяемости и модульности систем, а также на работу с высокими нагрузками. Поэтому в качестве основы для Backend-части мы, как правило, используем популярные фреймворки и СУБД.

Серверная часть большинства наших проектов основана на PHP-фреймворках Yii 2 и Laravel, а также же на NodeJS (для Real-time сервисов, ботов и тд).

Взаимодействие клиентской части с Backend-ом осуществляется, чаще всего, через, проектируемые нами для каждого проекта, REST API. Таким образом, мы добиваемся большей гибкости в интерфейсах, а также делаем единую серверную часть для веб-сайтов и мобильных приложений.

Попытаемся перечислить, чем же занимаются наши Backend-разработчики:

Разработка систем и сервисов:
— Проектирование архитектуры приложения и БД с учетом возможных нагрузок в режиме реального времени
— Реализация гибкой масштабируемости системы на основе кластеризации и репликации баз данных
— Построение запросов для выборки и анализа больших объемов аналитической и статистической информации
— Настройка серверов, кэширование кода и запросов к базам данных

Интеграция с программными системами:
— 1С, ERP-системы
— Платежные сервисы и эквайринг
— Социальные сети
— Службы доставки
— SMS-шлюзы

Поддержка существующих программных систем:
— Оптимизация существующих реляционных структур базы данных
— Рефакторинг кода
— Переработка компонентов системы для повышения производительности и безопасности

Создание сервисов, основанных на машинном обучении:
— Рекомендательные сервисы
— Анализ и обработка поступающих данных
— Автоматическое взаимодействие системы с пользователем

Разработка Real-time приложений:
— Системы с динамично меняющимися данными
— Онлайн-чаты
— Боты для мессенджеров
— Backend для игр
База сохрани эмоджи 🙏

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

Причиной является то, что некоторые UTF-символы не лежат в диапазоне BMP, и для их хранения требуется более 3 байт.

Если вы используете такую популярную СУБД как MySQL, то этих проблем можно избежать, используя кодировку utf8mb4, которая реализована в MySQL с версии 5.5.3.

Для решения нужно:
1) Необходимым текстовым полям в базе данных задать эту кодировку. Например, так:
CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci
2) Настроить соединение в конфигурации вашего фреймворка или CMS. Примеры:
https://bitbucket.org/snippets/OlegChulakovStudio/EqEj7L
Chramework

Помимо работы над проектами наших любимых клиентов, мы все время трудимся над разработкой внутренних инструментов и стартапов. Мы настолько любим это дело, что у нас даже есть для этого отдельная команда — Chulakov Lab:
https://chulakov.ru/lab

В этом квартале мы планируем запустить аж 9 студийных проектов. Девять, Карл! У нас тут и система учета документов, и бот управления проектами, и система подбора подрядчиков, и чего тут вообще только нет.

Мы задумались об оптимизации времени на верстку наших сервисов. И решили сделать корпоративную библиотеку компонентов (кнопочки, формочки, вот-это-вот-все).

Разумеется, у нас давно есть свой «бутстрап» (https://library.chulakov.ru), но он сделан по-старинке и не очень подходит для использования в React-среде.

Ребята с энтузиазмом восприняли идею создания библиотеки компонентов на React и сделали первую версию, буквально, за пару дней.

Торжественно окрестили новую библиотеку «Chramework» (Chulakov + Framework, ну вы поняли, да?) и уже начали использовать в разработке.

Так же, мы собрали себе документацию с демками с помощью react-styleguidist (хорошая штука). Вот поглядите:
https://chramework.chulakov.ru
THIS IS THE MOST IMPORTANT LINE

При разработке UI Kit на React для себя или клиента, важно обеспечить его легкую установку, использование и обновление во всех проектах.

Для этого лучше всего разместить UI Kit в NPM. С его помощью можно установить UI Kit в проект командой npm install, подключать компоненты используя import и добиться централизованного обновления библиотеки.

Когда мы занимались этим в первый раз, то столкнулись с массой ошибок при импорте компонентов библиотеки в проект. На определенном этапе поисков ответа мы наткнулись на статью разработчика, который, очевидно, очень много страдал пока искал решение этой же проблемы:
https://medium.com/@BrodaNoel/how-to-create-a-react-component-and-publish-it-in-npm-668ad7d363ce

Особого внимания заслуживает комментарий к заветной строчке в конфиге Webpack:
THIS IS THE MOST IMPORTANT LINE! :mindblow: I wasted more than 2 days until realize this was the line most important in all this guide

Надеемся, что эта информация сэкономит вам время, когда вы будете делать свой UI Kit на React или библиотеку, которую необходимо подключать и устанавливать подобным образом.
Прокрутка внутри всплывающих блоков в Safari на iOS

Frontend-разработчики, которые делают мобильные версии сайтов и веб-сервисов неминуемо сталкиваются с таким чудесным браузером как Safari на iOS. Воистину, этот браузер имеет свое уникальное мнение о многих вещах, касающихся отображения и поведения верстки.

Хотим рассказать решение одной из связанных с ним частых проблем, которая, мы уверены, сгубила нервы многих Frontend-разработчиков по всему миру. А именно проблему прокрутки внутри блоков, расположенных поверх страницы (таких как, например, модальные окна или боковые меню).

Увы, если положить блок, например, с помощью position: fixed поверх страницы, задать ему размеры и указать overflow: auto, то iOS Safari при его прокрутке устроит вам настоящий парад багов (https://vimeo.com/239318767/2240902c40):
1) Вместо (и во время) прокрутки в блоке двигается страница на фоне.
2) Как следствие, раскрываются/схлопываются верхняя и нижняя панели браузера.
3) Если контент блока меньше его высоты (прокрутка не нужна), то свайпы всегда прокручивают страницу на фоне.
4) Если блок полноэкранный, то его нижняя часть уходит под нижнюю панель браузера.
5) Меняется высота всплывающего блока и появляется пустота под ним.

Если изучить сайты с подобными элементами, то видно, что эту проблему либо игнорируют вообще, либо исправляют не полностью, либо чинят с помощью JavaScript-прокрутки вроде iScroll (что приводит к десятку других проблем и багов, вроде неверного расчета высоты прокручиваемой области или невозможности пользоваться элементами форм).

От этой проблемы и всех ее симптомов можно достаточно легко избавиться. Рассказываем как:

Отключить прокрутку страницы можно с помощью CSS, добавив position: fixed для body. Страница при этом прокрутится к началу, но эту мелочь легко исправить, установив, также, в стилях body значение свойства top соответствующее текущему положению прокрутки страницы.

В плане кода, решение проблемы легко умещается в один CSS-класс и пару функций (заблокировать/разблокировать прокрутку):
https://bitbucket.org/snippets/OlegChulakovStudio/RgBX8x

Посмотреть решение в действии вы можете, например, на бете новой мобильной версии онлайн-гипермаркета «Утконос» (https://www.utkonos.ru), презентацию и историю создания которой мы скоро опубликуем на сайте Студии.
Элементы интерфейса на React

Этим выпуском мы начинаем цикл мини-уроков, посвященный созданию различных элементов интерфейса сайтов и веб-приложений (табы, аккордеоны, выпадающие списки, календари и т.д.).

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

Начнем мы с такого распространенного элемента, как табы (переключение вкладок):
https://telegra.ph/EHlementy-interfejsa-na-React-Vypusk-1-Taby-10-24

Кстати, тем кто планирует заниматься разработкой интерфейсов для крупного бизнеса стоит заранее быть готовыми (и морально тоже) к ограничению на подключение зависимостей: при разработке систем для клиентов из финансовой и других подобных сфер, из соображений безопасности, в проект может быть запрещено подключать любые библиотеки и зависимости кроме проверенного минимума вроде React, Webpack и Babel.
Canvas 2D

Для работы с 2D-графикой в canvas, как правило, используют библиотеки (например, CreateJS или PixiJS). Но бывают задачи, которые лучше решать без использования сторонних решений, работая напрямую с функциями контекста.

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

Для решения подобных задач и для того, чтобы все наши разработчики имели представление о том, как «под капотом» работают все эти библиотеки, у нас есть лекция про canvas, которую мы рассказываем начинающим Frontend-разработчикам. Чтение лекции сопровождается интерактивной презентацией, где основные возможности показаны «вживую» с примерами кода:
https://dev.chulakov.ru/chulakov.edu.canvas/
Telegram как дистрибьютор контента

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

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

Что же делать, если контент удобно публиковать в Telegram, используя при этом все его возможности, но не хочется самостоятельно копировать публикации в другие источники, например, на сайт или в соцсети?

Если вы разработчик (или у вас под рукой есть такой), то решение достаточно простое: можно сделать небольшое приложение, которое будет работать с Telegram API, получать публикации и выводить/отправлять их в нужные вам платформы.

Сперва нужно зарегистрировать своего служебного бота в Telegram с помощью @BotFather, добавить его в нужный канал или чат.

Затем создать простое веб-приложение, которое будет работать с Telegram API, используя для авторизации токен вашего бота, полученный от @BotFather.

Для любого языка есть много готовых SDK, которые значительно упрощают работу с API. Например, в PHP-стеке мы используем https://packagist.org/packages/longman/telegram-bot, а в NodeJS — https://www.npmjs.com/package/node-telegram-bot-api.

При использовании SDK работать с сообщениями из Telegram будет очень легко. Вот примеры: https://bitbucket.org/snippets/OlegChulakovStudio/84a7Xz

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

Так, например, мы сделали раздел на сайте Студии с заметками нашего арт-директора (https://chulakov.ru/notes). Ссылкой на публикацию теперь легко поделиться, в том числе используя кнопки популярных социальных сетей.
Микровзаимодействия 👆

Для многих веб-студий и digital-агентств результатом работы по созданию дизайна являются статичные макеты страниц или экранов.

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

Например, много внимания уделяется микровзаимодействиям, которые значительно повышают отзывчивость интерфейса, позволяют пользователю лучше в нем ориентироваться и эффективно работать с системой.

В качестве базовых микровзаимодействий можно назвать реакции на тапы пользователя: «вдавливание» и «затухание» элементов под «весом» курсора, волны от позиции нажатия и тд.

Много таких реакций мы проработали, например, в рамках концепции сайта для Райффайзенбанк: https://raiffeisen.chulakov.ru/home.php

Летом мы поставили себе цель максимально упростить и ускорить процесс интеграции базовых микровзаимодействий в новые продукты на React. Для этого мы разработали универсальный конфигурируемый компонент <Tap />, работу которого вы можете посмотреть на бете новой мобильной версии сайта онлайн-гипермаркета «Утконос», нажав на любую ссылку или кнопку: https://www.utkonos.ru (смотреть с телефона).

Компонент прошел полевые испытания, и мы с радостью готовы поделиться первой публичной версией со всеми разработчиками. С помощью этого компонента добавлять базовые микровзаимодействия к любым интерактивным элементам веб-приложений и сайтов становится очень легко.

Сами посмотрите:
https://react-interactions.chulakov.ru

Инструкция по установке и подключению доступна в репозитории на GitHub:
https://github.com/OlegChulakovStudio/react-interactions
В ногу со временем

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

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

При работе с подобными задачами обрабатывать и пересчитывать время на стороне мобильного приложения не оптимально: приходится дублировать алгоритмы как для приложений на каждой ОС (iOS, Android), так и на стороне сервера. Кроме того, несоответствие во времени может возникнуть при разнице в версиях приложений, что, разумеется, недопустимо, когда речь идет о здоровье.

Для решения всех этих проблем мы выбрали принцип «тонкого» клиента: централизовали всю логику конвертации времени внутри backend-части системы и полностью исключили ее из мобильных приложений.

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

Вся информация о времени и датах хранится в базе данных как метки Unix Timestamp в формате UTC, который имеет нулевое часовое смещение, и с легкостью пересчитывается в дату и время любого часового пояса.
Синхронизация времени с сервером

В продолжение темы прошлой заметки давайте рассмотрим частую для веб-приложений проблему несоответствия времени на компьютере пользователя и на сервере.

Например, в нашей партнерской программе (https://partners.chulakov.ru) компании должны прислать клиенту свое коммерческое предложение в течение 24 часов с момента начала участия в тендере. Когда партнер открывает свой кабинет, из REST API приходит информация о тендере и время, при наступлении которого backend перестанет принимать предложения. Оставшееся число часов, минут и секунд отображается в таймере обратного отсчета.

Если с помощью JavaScript просто отсчитывать время до наступления момента, полученного из API, то мы получим рассинхронизацию работы frontend- и backend-логики, соответствующую тому, насколько часы в ОС пользователя спешат или отстают относительно часов сервера. Форма либо слишком рано заблокируется, либо будет доступна в то время, когда прием предложений уже закрыт в backend-части.

Самое простое решение подобных проблем — один раз запросить текущее время сервера, вычислить разницу между ним и временем пользователя, а затем использовать полученное значение для смещения всех таймеров в JavaScript.

Для удобства работы всю логику можно оформить в специальный модуль:
https://bitbucket.org/snippets/OlegChulakovStudio/9ejdXk

Или так, если предпочитаете работать с форматированным временем:
https://bitbucket.org/snippets/OlegChulakovStudio/rejKe5
3... 2... 1,5... 1... 0

Кстати, про обратный отсчет в JavaScript: часто в интернете можно увидеть, как разработчики делают ежесекундный setInterval, при каждом вызове которого уменьшают оставшееся время на секунду и выводят значение в интерфейсе. Одним словом, делают что-то вроде этого:
https://bitbucket.org/snippets/OlegChulakovStudio/de4q4L

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

Чтобы избежать таких проблем, нужно производить вычисления, опираясь на время, до которого идет отсчет:
https://bitbucket.org/snippets/OlegChulakovStudio/ae4q48
Компонент, я твой отец

При разработке веб-приложений на React нередко возникает необходимость переиспользовать логику компонентов, полностью меняя их внешний вид. Чаще всего для этого используют Компоненты Высшего Порядка (Higher-Order Components), но есть и другие подходы, которые, в зависимости от решаемой задачи, могут оказаться более удобными.

Рассмотрим менее известный способ под названием «Function as Child Components» (FaCC), при котором компонент получает в качестве потомков не элементы, а функцию, что дает возможность управлять рендером из родителя.

Например, если в интерфейсе много выпадающих списков с одинаковой логикой (показать/скрыть), но выглядят они абсолютно по-разному, то решение с помощью FaCC может выглядеть вот так:
https://bitbucket.org/snippets/OlegChulakovStudio/LeEGkg

Интерактивное демо с более подробным кодом:
https://codesandbox.io/s/8x2183nj5j

Также, чтобы лучше понять ситуации, в которых может быть полезен этот подход, можно посмотреть популярные библиотеки, которые его используют: react-motion, react-media, PayPal Downshift.
Карты, боты, GMT+2

Для корректной работы со временем многим системам необходима информация о часовом поясе клиента. В веб-приложениях эту проблему решают за счет выбора города или зоны в интерфейсе или в профиле пользователя.

При разработке PM Bot (кстати, скоро релиз) ребята из нашей Лаборатории узнали, что Telegram API не передает информацию о таймзоне собеседника, а привычные механики выбора пояса неприменимы для ботов.

Что же делать? Выводить клавиатуру с каждым вариантом? Получается слишком громоздко и неудобно. Просить отправить сообщение с названием города или пояса? Могут быть ошибки как при вводе текста, так и на этапе его обработки ботом.

Мы остановились на удобном для пользователя способе с автоматическим определением на основе геопозиции.

Не так давно в Telegram API появилась возможность расширять варианты ответов в клавиатуре действиями request_location и request_contact. Теперь для получения координат пользователя достаточно при отправке сообщения от бота настроить параметр reply_markup следующим образом:
{
"keyboard": [[
{ "text": "Отправить мою геопозицию", "request_location": true },
{ "text": "Не сейчас" }
]],
"resize_keyboard": true,
"one_time_keyboard": true
}

После того как бот получил широту и долготу собеседника, на их основе нетрудно получить временную зону. Для этого не нужно изобретать «велосипед» и можно воспользоваться существующими сервисами вроде Google Maps Time Zone API.

Механику с определением часового пояса по координатам можно использовать не только в ботах, но и, например, в веб-приложениях (в связке с HTML5 Geolocation). Однако следует учитывать, что пользователь может отказать в предоставлении своей позиции, а устройство или приложение может не иметь такой возможности.
Операция «И»

В последние годы многие Frontend-разработчики начинают использовать трендовые технологии раньше, чем изучат основы JavaScript, что порой приводит к неожиданным для них багам.

Например, для скрытия пустого списка новички в React могут использовать, казалось бы, привычный многим код:
<div>
{props.tasks.length &&
<TaskList tasks={props.tasks} />
}
</div>

Увы, когда props.tasks окажется пустым массивом, вместо списка будет отрисовано число 0. Особенно везучие разработчики узнают об этом, когда проект уже находится в production.

Чтобы понять причину такого поведения, следует вспомнить, как работает логический оператор && в JavaScript: он интерпретирует значения как логические, но результат возвращает без преобразования.

В данном примере, если массив окажется пустым, логическое И преобразует 0 в false и остановит вычисление, так как результат ложный и вернет 0.

Для избежания таких проблем, убедитесь, что выражение перед && всегда является логическим (boolean).
Я пришлю ее вам по кусочкам

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

Рассмотрим два примера. Что не так с первым кодом и почему лучше использовать второй?

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

Также заметим, что в современных фреймворках есть готовые методы для отправки файлов.