Php выгрузка в excel
I am using PHPEXxcel to export an HTML Table generated using MYSQL and its like this.
Its working but it saves the xlsx file in the root folder without showing to user any signs that its being downloaded. This code rund when i click a button.now, can i make it to be downloaded like we download a mail attachment and showing the user in the front end that its being downloaded along with the location.
With this, i am getting what i wanted above but the xls file downloaded when opened shows the message 'The File you are trying to open 'filename' is in a different format than the specified extension. etc.Do you want to open now?
On opening it contains either the entire HTML Page or its simply blank. Can anybody help me.
Note that you are not creating an HTML Page. HTML is a markup used for web pages. With PHPExcel, you are creating an Excel file using either the BIFF-8 file format or the OfficeOpenXML format.
4 Answers 4
Spreadsheets 101
There are many different spreadsheet file formats, each with their own different filename extensions, and that can be sent to a web browser using different mime types. These are described in the PHPExcel documentation, and each has its own different Writer in PHPExcel. You're mismatching two different formats
Used by Microsoft Excel between versions 95 and 2003 File
extension: xls
PHPEXcel Writer: PHPExcel_Writer_Excel5
Mime Type: application/vnd.ms-excel
Used by Microsoft Excel since version 2007
File extension: xlsx
PHPEXcel Writer: PHPExcel_Writer_Excel2007
Mime Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
Don't mix and match: if you do, then Excel will (and justifiably) complain. If you want a BIFF file, use PHPExcel's BIFF Writer (Excel5), a file extension of .xls, and the mime type listed above for BIFF Format. If you want an OfficeOpenXML file, then use PHPExcel's Excel2007 Writer, a file extension of .xlsx, and the mime type listed above for OfficeOpenXML.
EDIT
Note that the examples provided with the PHPExcel distribution include 01simple-download-xls.php and 01simple-download-xlsx.php to demonstrate exactly what you want
К написанию данного топика меня подтолкнула одна заметка о генерации xls в PHP.
Способ, представленный в той заметке действительно очень прост, но не всегда может быть удобен.
Есть множество других способов передать табличные данные из PHP в Excel, я опишу тот, который показался мне наиболее простым и функциональным. Нужно особенно отметить, что что я не говорю о генерации xls файла, а лишь предлагаю пользователю открыть полученные данные при помощи Excel так, что пользователи не искушённые в программировании не заметят подлога.
Итак, первое что необходимо сделать — разместить на нашей страничке ссылку на скрипт генерирующий следующие заголовки:
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private", false);
header("Content-Type: application/x-msexcel");
header("Content-Disposition: attachment; filename=\"" . iconv('UTF-8', 'CP1251', $object->getFileName()) . "\";");
header("Content-Transfer-Encoding: binary");
header("Content-Length: " . $object->getFileSize());
$object — сферический объект в вакууме, который каждый читатель реализует так, как ему больше нравится. Назначение геттеров getFileName() и getFileSize() понятно из названий. Здесь стоит выделить один неочевидный нюанс (спасибо savostin за то что напомнил об этом) — getFileName() конечно может возвращать любое имя файла, но если вы хотите что бы браузер предложил открыть полученный контент в Excel, то расширение файла должно быть xls.
Ничего нового я пока не рассказал, все это придумано до меня, впрочем как и то что будет описано ниже.
Как верно было отмечено в комментариях к заметке о генерации xls в PHP, Excel гораздо быстрее работает с XML. Но самое главное преимущество, пожалуй, все же не в скорости, а в гораздо более широких возможностях. Углубляться в дебри я не стану, а лишь приведу простой пример, и ссылку на подробное описание всех тегов.
Итак, после того как заголовки сгенерированны, нам нужно отдать пользователю собственно данные. Я обычно заворачиваю генерацию таблицы в отдельный метод:
echo $object->getContent();
А таблицу генерирую при помощи Smarty:
Как видно из кода, в шаблон передается массив $data содержащий два массива — строку заголовка таблицы и собственно данные.
Стоит отметить что использовать шаблонизатор только для генерации XML несколько накладно, и получить XML можно множеством других способов. В моем конкретном случае генерация XML это лишь маленькая плюшка в большом проекте, где без шаблонизатора не обойтись.
В качестве примера я привел простейшую таблицу, при желании можно манипулировать гораздо большим числом атрибутов. Это особенно приятно, если учесть, что для реализации не требуются никакие сторонние библиотеки.
Описанный метод несколько лет работает на одном проекте и ни один пользователь до сих пор не заподозрил, что открываемые им данные не являются документом MS Office.
Подробнее о структуре XML используемой в MS Excel можно почитать в MSDN XML Spreadsheet Reference
Возможность создания Excel-документов в общих чертах уже была описана на Хабре, но полной информации из этих статей мне получить не удалось. Пришлось заняться собственными изысканиями, результатами которых я хотел бы с Вами поделиться. Данная статья будет полезна и новичкам, и профессионалам, столкнувшимся с проблемой динамического формирования Excel-документов.
Это всего лишь первая часть серии статей, которыми хотелось бы поделиться с общественностью. В последующих статьях будут более подробно рассмотрены некоторые способы и нюансы выгрузки xls-файлов.
Введение
Не хочу распространяться на тему того, зачем необходима выгрузка в Excel. Мне кажется, что это вполне очевидно: в формате MS Excel достаточно удобно предоставлять пользователю загружаемые данные. Это могут быть прайс-листы, каталоги или любая подобная служебная, статистическая и иного рода информация.
Сразу хочу оговориться, что в статье рассматривается работа с документами через COM-объекты. Данный метод таботает только на Windows-платформах. Другими словами, если Вы предпочитаете *nix-хостинг, этот метод Вам не подходит.
Синтаксис
Создание COM-объекта осуществляется следующим образом:
$my_com_object = new COM($object_class);
, где
$my_com_object — новый COM-объект;
$object_class — id-класс требуемого объекта.
Для создания Excel-документов переменной $object_class необходимо задать значение «Excel.Application» либо «Excel.sheet».
$xls = new COM("Excel.Application");
После создания нового COM-объекта, можно обращаться к его свойствам и методам:
$xls = new COM("Excel.Application"); // Создание объекта
$xls->Application->Visible = 1; // Делаем объект видимым
$xls->Workbooks->Add(); // Добавляем новую книгу (создаём документ)
$rangeValue = $xls->Range("A1");
$rangeValue->Value = "Декорация текста: жирный, подчеркнутый, наклонный";
$rangeValue = $xls->Range("A2");
$rangeValue->Value = "Размер шрифта: 14";
$rangeValue = $xls->Range("A3");
$rangeValue->Value = "Тип шрифта: Arial";
$range=$xls->Range("A1:J10"); // Указываем область ячеек
$range->Select(); // Выделяем эту область
$fontRange=$xls->Selection(); // Присваиваем переменной выделенную область
// Отформатируем текст в выделенной области
$fontRange->Font->Bold = true; // Жирный
$fontRange->Font->Italic = true; // Курсив
$fontRange->Font->Underline = true; // Подчеркнутый
$fontRange->Font->Name = "Arial"; // Тип шрифта
$fontRange->Font->Size = 14; // Размер шрифта
?>
Открытие, запись, закрытие документа
Общие возможности
- создать новый документ
- открыть ранее созданный документ
- сохранить открытый документ
- закрыть документ
Создание нового документа
- создаем «связь» между PHP и Excel (создается дескриптор, как при работе с файлами)
- указываем, будет ли визуально открыта программа или нет
- указываем программе через дескриптор, что нужно открыть новый документ
Открытие ранее созданного документа
Открытие документа можно сделать при помощи метода Open() объекта Workbooks().
В передаваемом методу Open() параметре нужно указать имя открываемого файла:
$xls = new COM("Excel.Application"); // Создаем новый COM-объект
$xls->Application->Visible = 1; // Делаем его видимым
$xls->Workbooks->Open("C:\my_doc.xls"); // Открываем ранее сохраненный документ
?>
Внимание! Если указать не полный, а относительный путь, то поиск открываемого файла будет происходить не на сервере, а на компьютере пользователя. По умолчанию это папка «Мои документы».
Сохранение открытого документа
Сохранение открытого документа производится при помощи метода SaveAs() объекта Workbooks():
$xls = new COM("Excel.Application"); // Создаем новый COM-объект
$xls->Application->Visible = 1; // Делаем его видимым
$xls->Workbooks->Add();
$range=$xls->Range("A1"); // Выбираем ячейку A1
$range->Value = "Проба записи"; // Вставляем значение
// Сохраняем документ
$xls->Workbooks[1]->SaveAs("my_doc.xls");
$xls->Quit(); //Закрываем приложение
$xls->Release(); //Высвобождаем объекты
$xls = Null;
$range = Null;
?>
Хочу отдельно отметить, что высвобождение объектов — это очень хорошо и правильно. Да сгорят в священном очищающем пламени костров Инквизиции те, кто считает иначе.
Закрытие документа
Закрытие документа производится методом Quit().
$xls = new COM("Excel.Application"); // Создаем новый COM-объект
$xls->Application->Visible = 1; // Делаем его видимым
$xls->Workbooks->Add();
$range=$xls->Range("A1"); // Выбираем ячейку A1
$range->Value = "Что-то записываем"; // Вставляем значение в ячейку
// Сохраняем документ
$xls->Workbooks[1]->SaveAs("my_doc.xls");
$xls->Quit(); // Закрываем приложение
$xls->Release(); // Высвобождаем объекты
$xls = Null;
$range = Null;
?>
Заключение
Если статья оказалась Вам полезна и интересна, буду рад подготовить продолжение, где более подробно будут рассматриваться методы работы с листами документов, ячейками и границами.
Разумеется, если это кому-то интересно и необходимо для работы.
PHPExcel позволяет производить импорт и экспорт данных в excel. Применять различные стили оформления к отчетам. В общем, все на высоте. Даже есть возможность работы с формулами. Только необходимо учитывать, что вся работа (чтение и запись) должна вестись в кодировке utf-8.
Установка библиотеки
С помощью библиотеки PHPExcel можно записывать данные в следующие форматы:
- Excel 2007;
- Excel 97 и поздние версии;
- PHPExcel Serialized Spreadshet;
- HTML;
- PDF;
- CSV.
Импорт данных из PHP в Excel
Рассмотрим пример по формированию таблицы умножения.
Рассмотрим еще на примере три полезные инструкции:
- $sheet->getColumnDimension('A')->setWidth(40) – устанавливает столбцу “A” ширину в 40 единиц;
- $sheet->getColumnDimension('B')->setAutoSize(true) – здесь у столбца “B” будет установлена автоматическая ширина;
- $sheet->getRowDimension(4)->setRowHeight(20) – устанавливает четвертой строке высоту равную 20 единицам.
Также обратите внимание на следующие необходимые для работы с отчетом методы:
- Методы для вставки данных в ячейку:
- setCellValue([$pCoordinate = 'A1' [, $pValue = null [, $returnCell = false]]]) — принимает три параметра: координату ячейки, данные для вывода в ячейку и третий параметр эта одна из констант типа boolean: true или false (если передать значение true, то метод вернет объект ячейки, иначе объект рабочего листа);
- setCellValueByColumnAndRow([$pColumn = 0 [, $pRow = 1 [, $pValue = null [, $returnCell = false]]]]) — принимает четыре параметра: номер столбца ячейки, номер строки ячейки, данные для вывода в ячейку и четвертый параметр действует по аналогии с третьим параметром метода setCellValue().
- getCell([$pCoordinate = 'A1']) — принимает в качестве параметра координату ячейки;
- getCellByColumnAndRow([$pColumn = 0 [, $pRow = 1]]) — принимает два параметра в виде номеров столбца и строки ячейки.
Как мы видим, вышеприведенные методы являются парными. Поэтому мы можем работать с ячейками используя строковое или числовое представление координат. Что конечно же является дополнительным преимуществом в работе.
Оформление отчета средствами PHP в Excel
Очень часто возникает необходимость выделить в отчете некоторые данные. Сделать выделение шрифта или применить рамку с заливкой фона для некоторых ячеек и т.д. Что позволяет сконцентрироваться на наиболее важной информации (правда может и наоборот отвлечь). Для этих целей в библиотеке PHPExcel есть целый набор стилей, которые можно применять к ячейкам в excel. Есть конечно в этой библиотеке небольшой “минус” – нельзя применить стиль к нескольким ячейкам одновременно, а только к каждой индивидуально. Но это не создает дискомфорта при разработке web-приложений.
Назначить стиль ячейке можно тремя способами:
- Использовать метод applyFromArray, класса PHPExcel_Style. В метод applyFromArray передается массив со следующими параметрами:
- fill — массив с параметрами заливки;
- font — массив с параметрами шрифта;
- borders — массив с параметрами рамки;
- alignment — массив с параметрами выравнивания;
- numberformat — массив с параметрами формата представления данных ячейки;
- protection — массив с параметрами защиты ячейки.
- pCellStyle – данный параметр является экземпляром класса PHPExcel_Style;
- pRange – диапазон ячеек.
Заливка
Значением параметра fill является массив со следующими необязательными параметрами:
- type — тип заливки;
- rotation — угол градиента;
- startcolor — значение в виде массива с параметром начального цвета в формате RGB;
- endcolor — значение в виде массива с параметром конечного цвета в формате ARGB;
- color — значение в виде массива с параметром начального цвета в формате RGB.
Или можно использовать следующие методы:
Вставка изображений
Довольно редко, но бывает полезным произвести вставку изображения в отчет. Это может быть логотип, схема и т.д. Для работы нам понадобятся следующие методы:
- setPath([$pValue = '', [$pVerifyFile = true]]) — данный метод принимает два параметра. В качестве первого параметра указывается путь к файлу с изображением. А второй параметр имеет смысл указывать, если необходимо осуществлять проверку существования файла (может принимать одно из значений true или false).
- setCoordinates([$pValue = 'A1'])) — принимает на вход один параметр в виде строки с координатой ячейки.
- setOffsetX([$pValue = 0]) — принимает один параметр со значением смещения по X от левого края ячейки.
- setOffsetY([$pValue = 0]) — принимает один параметр со значением смещения по Y от верхнего края ячейки.
- setWorksheet([$pValue = null, [$pOverrideOld = false]]) — этот метод принимает на вход два параметра. Первый является обязательным, а второй нет. В качестве первого параметра указывается экземпляр класса PHPExcel_Worksheet (текущий активный лист). Если в качестве значения второго параметра передать true, то если лист уже был назначен ранее – произойдет его перезапись и соответственно изображение удалится.
Код демонстрирующий алгоритм вставки изображения приведен ниже:
Вот так выглядит отчет со вставленным изображением:
Шрифт
В качестве значения параметра font указывается массив, который содержит следующие необязательные параметры:
- name — имя шрифта;
- size — размер шрифта;
- bold — выделять жирным;
- italic — выделять курсивом;
- underline — стиль подчеркивания;
- strike — перечеркнуть;
- superScript — надстрочный знак;
- subScript — подстрочный знак;
- color — значение в виде массива с параметром цвета в формате RGB.
Или воспользоваться следующими методами:
Рамка
В качестве значения параметра borders указывается массив, который содержит следующие необязательными параметры:
- тип рамки — (top|bootom|left|right|diagonal|diagonaldirection);
- style — стиль рамки;
- color — значение в виде массива с параметром цвета в формате RGB.
Так же можно прибегнуть к использованию следующих методов:
$PHPExcel_Style->getBorders()->getLeft()->applyFromArray(array(‘style’ =>PHPExcel_Style_Border::BORDER_DASHDOT,’color’ => array(‘rgb’ => ’808080')));
$PHPExcel_Style->getBorders()->getRight()->applyFromArray(array(‘style’ =>PHPExcel_Style_Border::BORDER_DASHDOT,’color’ => array(‘rgb’ => ’808080')));
$PHPExcel_Style->getBorders()->getTop()->applyFromArray(array(‘style’ =>PHPExcel_Style_Border::BORDER_DASHDOT,’color’ => array(‘rgb’ => ’808080')));
$PHPExcel_Style->getBorders()->getBottom()->applyFromArray(array(‘style’ =>PHPExcel_Style_Border::BORDER_DASHDOT,’color’ => array(‘rgb’ => ’808080')));
$PHPExcel_Style->getBorders()->getDiagonal()->applyFromArray(array(‘style’ => PHPExcel_Style_Border::BORDER_DASHDOT,’color’ => array(‘rgb’ => ’808080')));
$PHPExcel_Style->getBorders()->setDiagonalDirection(array(‘style’ =>PHPExcel_Style_Border::BORDER_DASHDOT,’color’ => array(‘rgb’ => ’808080'))).
Выравнивание
Значением параметра alignment является массив, который принимает на вход четыре необязательных параметра:
- horizontal — константа горизонтального выравнивания;
- vertical — константа вертикального выравнивания;
- rotation — угол поворота текста;
- wrap — разрешить перенос текста;
- shrinkToFit — изменять ли размер шрифта при выходе текста за область ячейки;
- indent — отступ от левого края.
Или использовать следующие методы:
Формат представления данных
Параметр numberformat представляет собой массив, который включает только один параметр: code — формат данных ячейки.
А можно и воспользоваться методом:
Защита ячеек
В качестве значения параметра protection выступает массив, который содержит два необязательных параметра:
- locked — защитить ячейку;
- hidden — скрыть формулы.
Или использовать следующие методы:
Теперь мы знаем, какие есть настройки стилей и какие присутствуют параметры у каждого стиля. Сейчас мы к ячейкам таблицы применим стиль оформления, но проделаем это тремя способами. Первый способ заключается в создании массива настроек, который в качестве параметра мы передадим в метод applyFromArray, класса PHPExcel_Style.
Далее мы применим созданный нами стиль к ячейкам excel.
Сейчас применим тот же стиль, но используя другую методику.
Вот что у нас получилось:
Для получения данных о стиле конкретной ячейки необходимо использовать один из следующих методов, который вернет экземпляра класса PHPExcel_Style:
- getStyleByColumnAndRow([$pColumn = 0 [, $pRow = 1]]) – применяется если требуется обратиться к ячейке по числовым координатам. Методу необходимо передать два параметра в виде номеров столбца и строки ячейки;
- getStyle([pCellCoordinate = 'A1']) – используется для обращения по строковой координате ячейки. Методу требуется передать один параметр, это строковое представление координаты.
А теперь рассмотрим третий способ назначения стиля ячейкам путем дублирования стиля. Пример использования представлен ниже (предполагается, что к ячейке “B2” применен некий стиль и мы его хотим продублировать для диапазона ячеек “F2:F10”):
Добавление комментариев
Я думаю, что не часто кто-то пользуется возможностью добавления комментариев к ячейкам, но это сугубо мое личное мнение, однако такая возможность имеется. Добавить комментарий к ячейке довольно просто, что видно из примера ниже:
Следует заметить, что при повторном вызове метода createTextRun() новый комментарий добавится к уже существующему, а не заменит его. Следует отметить, что данный метод возвращает объект класса PHPExcel_RichText_Run, у которого имеются методы для установки и получения параметров шрифта:
- getFont() – возвращает объект класса для работы со шрифтами PHPExcel_Style_Font.
- setFont([$pFont = null]))]) – данному методу требуется передать в качестве параметра объект класса PHPExcel_Style_Font.
Вот какой комментарий мы должны получить:
Вставка ссылки
Вставка ссылок в ячейку тоже не вызывает каких-либо затруднений, что можно видеть из нижеописанного примера:
Чтение данных из Excel
Формировать отчеты и применять к ним стили это конечно отлично. Но на этом возможности библиотеки PHPExcel не заканчиваются. Ну что же, посмотрим на что она еще способна. А способна она еще и читать данные из файлов формата *.xls / *.xlsx.
С помощью библиотеки PHPExcel можно читать следующие форматы:
- Excel 2007;
- Excel 5.0/Excel 95;
- Excel 97 и поздние версии;
- PHPExcel Serialized Spreadshet;
- Symbolic Link;
- CSV.
Для работы нам понадобятся объекты двух классов:
- PHPExcel_Worksheet_RowIterator – используется для перебора строк;
- PHPExcel_Worksheet_CellIterator – используется для перебора ячеек.
Для демонстрации выведем данные из таблицы с информацией об автомобилях.
Пример чтения файла представлен ниже:
Первый вариант
Второй вариант
В первом варианте мы производим чтение данных, из ячеек используя итераторы. А во втором, мы используем индексную адресацию для обращения и получения данных из ячеек листа. Получить данные о количестве строк и столбцов, можно воспользовавшись следующими методами класса PHPExcel_Worksheet:
- getHighestColumn() – возвращает символьное представление последнего занятого столбца в активном листе. Обратите внимание: не индекс столбца, а его символьное представление (A, F и т.д.);
- getHighestRow() – возвращает количество занятых строк в активном листе.
Другие полезные методы
Возможностей по работе с отчетами формата excel с использованием PHP как мы видим, достаточно много. Но мы рассмотрим еще несколько полезных методов, которые могут оказаться весьма полезны в работе:
- getMergeCells() – с помощью данного метода принадлежащего классу PHPExcel_Worksheet можно получить информацию обо всех объединенных ячейках в листе;
- setPreCalculateFormulas([$pCellStyle = true]) – данный метод необходимо использовать если требуется произвести расчет формул в листе (он имеется у двух классов: PHPExcel_Writer_Excel5 и PHPExcel_Writer_Excel2007). В рассматриваемый метод передается параметр типа boolean: true или false (если передать значение true, то расчет формул произойдет перед сохранением файла автоматически, иначе расчета формул не последует). Использование данного метода может оказаться полезным если созданный файл потребуется загрузить, к примеру на Google Drive. Ведь в таком случае расчет формул не будет произведен автоматически указанным сервисом и здесь вся ответственность ложиться на нас;
- stringFromColumnIndex([$pColumnIndex = 0]) – данный метод позволяет определить по номеру столбца его символьное представление, для этого в качестве параметра необходимо передать его номер;
- columnIndexFromString([$pString = 'A']) – с помощью данного метода можно определить номер столбца по его символьному представлению, для этого в качестве единственного параметра необходимо передать его обозначение.
Примечание: Методы stringFromColumnIndex и columnIndexFromString примечательны тем, что их можно использовать без создания объекта класса. Пример использования представлен ниже:
С помощью продемонстрированных возможностей, можно формировать и считывать любые отчеты в виде файлов, формата excel. А также были продемонстрированы почти все возможные методы для работы со стилями.
У многих при работе с PHP в связке с MySQL возникает такая потребность, как экспорт данных из базы в формат xls, для того чтобы люди, которым нужны эти данные, обрабатывали их в программе Excel или просто пользователям было удобно смотреть эти данные. Недавно у меня возникла такая потребность и сегодня я расскажу, как это дело можно реализовать.
Сразу скажу, что этот способ достаточно простой, но данные выгружаются нормально.
Для начала приведу пример конечного xls файла, в программе Excel выгрузка будет выглядеть примерно так:
Другими словами, никаких картинок, стилей выгружено не будет, только заголовки столбцов и сами данные.
До того как я пришел именно к такому варианту выгрузки я пробовал выгружать в формат csv, но получалось немного коряво, потом пробовал отрисовывать таблицу и сохранять ее с расширением xls, также получалось какая-то ерунда, способ, который я сейчас опишу, меня полностью устроил, и сейчас с Вами я им поделюсь.
Для начала приведу весь код, который я максимально прокомментировал, можете выделить его и сохранить с расширением php и пробовать, только не забудьте прописать настройки подключения к базе данных.
Экспорт данных из MySQL в Excel на PHP
А еще чтобы Вы понимали, какие данные я выгружаю, приведу пример простой таблицы в БД (у меня ее название test):
Тестовая таблица:
id firstname name 1 Иванов Иван 2 Петров Петр 2 Петров2 Петр2 Код:
Вся идея здесь заключается в функции pack(), которая упаковывает данные в бинарную строку, а мы в свою очередь последовательно заполняем эту строку данными, которые мы выгрузили из базы данных MySql с помощью обычной функции mysql_query().
Для того чтобы проверить работоспособность данного кода, с учетом того, что Вы настроили подключение к базе данных и создали аналогичную таблицу, можете послать такой запрос:
И у Вас должно выгрузиться две строки с id равным 2.
И теперь каждый, которому Вы разрешите выгружать данные может легко экспортировать их на свой локальный компьютер через web интерфейс. Данный способ удобен как для корпоративных пользователей, если Вы разрабатываете приложение для своей организации, так и для пользователей Вашего web сайта в Интернете. Надеюсь, данный способ Вам помог. Удачи!
Заметка! Если Вас интересует язык SQL, рекомендую пройти мой онлайн-курс по основам SQL, который ориентирован на изучение SQL как стандарта, таким образом, Вы сможете работать в любой системе управления базами данных. Курс включает много практики: онлайн-тестирование, задания и многое другое.
Читайте также: