Напиши программу на php, которая обрабатывает файл prices.csv, при запуске проверяет существование файлов ostatki.txt и pusto.txt, если эти файлы не существуют, создаёт их. Если файлы существуют, очищает их содержимое. Также если не существует, то создается база sqlite ostatki.db с с двумя таблицами: таблица ostatki с полями artikul ( число), tovar (текстовое), qty ( числовое) и таблица pusto с полями artikul (число), tovar (числовое), qty (текстовое) . Также добавь вывод ошибок php в начале файла.
Если скрипт запускается первый раз ( это можно проверить по отсутствию базы ostatki.db)- если файла базы нет ostatki.db, она создается как написано выше и запуск считается первым, в этом случае идет обработка файла prices.csv по таким правилам:
файл prices.csv содержит разделители ; ( точка с запятой)
обработка файла prices.csv начинается со второй строки.
2ая колонка в prices.csv это переменная artikul (артикул товара), 3я колонка это name (название товара), 14ая колонка это qty ( количество), считываем все данные из prices.csv построчно, для ускорения процесса используем массив, записываем данные в базу данных ostatki.db в таблицу ostatki по соответствующим названиям полей и переменных ( artikul в artikul и так далее, при условии что в 14й колонке содержится любое число, если в 14й колонке пусто, тогда данные artikul, tovar записываются в таблицу pusto, а в поле qty этой таблицы pusto записывается текстовое значение zero.
Происходит запись лог файлов ostatki.txt и pusto.txt по таким правилам:
в файл ostatki.txt идет построчная запись товаров с нулевыми остатками, то есть из таблицы ostatki берется товар где qty=0 и в этом случае формируется запись: Товар artikul name закончился, проверьте остатки! И так до тех пор, пока будут проверены все нулевые значения таблицы ostatki в поле qty в базе ostatki.db
в файл pusto.txt построчно записываются значения из таблицы pusto в таком формате Товар artikul name не был заведён по каким-то причинам. После первого запуска идет отправка данных с помощью функции
maillogfile, ее описание в конце текста. И после запуска этой функции maillogfile идет остановка программы, она считается завершенной.
.
При повторном запуске программы ( повторным считается запуск если существует база ostatki.db)
идет проверка на изменение данных в базе данных при сравнении с файлом prices.csv по таким правилам ( начиная со второй строки):
Если в файле prices.csv где 2ая колонка в prices.csv это переменная artikul (артикул товара), 3я колонка это name (название товара), 14ая колонка это qty ( количество), считываем все данные из prices.csv построчно ( ускоряем процесс с помощью массива), если определяется что qty=0 нужно проверить совпадение в базе данных ostatki.db в таблице ostatki по артикулу ( artikul), если в таблице также в qty находится 0, то ничего не делаем, и запись в лог файл ostatki.txt не производим. Если в таблице prices.csv qty=0 ( это 14ая колонка), а в базе данных ostatki.db в таблице ostatki значение qty больше нуля, тогда делаем запись в лог файл ostatki.txt в формате Товар artikul name закончился, проверьте остатки!
Если при сравнении prices.csv и таблицы ostatki в базе данных ostatki.db при совпадении artikul число qty отличается от нуля ( не пустая строка и не отсутствие значения), и qty в prices.csv отличается от qty в таблице ostatki то делаем перезапись значения qty в базе данных.. Если artikul в prices.csv не находится в ostatki.db в таблице ostatki, при втором и последующих запусках программы, значит данного товара еще не было и создается новая строка с данными artikul, tovar, qty и также идёт запись в ostatki.txt такого вида: Добавлен товар artikul name с остатком qty.
Также проверяем проходя 2, 3, 14 колонку файла prices.csv и таблицу pusto в базе данных, если artikul содержит qty от 0 и выше, и при этом данный artikul содержится в таблице pusto, то удаляем эту строку из базы данных из таблицы pusto.
Также идёт проверка таблицы pusto, если в файле prices.csv есть пустые значения в qty ( 14ая колонка), то есть это не 0 и не число, и такое же точно значение уже есть в таблице pusto по значению artikul, и в qty находится zero, то в файл pusto.txt ничего не пишем и проверяем дальше. В итоге после всех проверок
Запускается функция для отправки maillogfile, ее описание ниже.
Функция maillogfile содержит отправку по заданному адресу с другого заданного адреса с использованием библиотеки Phpmailer ( она находится в папке PHPMailer/src/, адрес куда отправлять берет из файла email.txt, откуда отправлять и другие настройки берет из файла email.cfg в формате json, пример содержимого email.cfg с соответствующими настройками, чтобы ты знал как создать функцию maillogfile с использованием данных файлов в виде настроек приведены ниже в кавычках {}
"smtp_host": "smtp.mail.ru",
"smtp_username": "de--@Mail.ru",
"smtp_password": "H--—9H",
"smtp_port": 465
“Name”: ”Dimitriy”
Здесь Name это имя отправителя, все остальные данные совпадают с переменными..
Эта функция при запуске отправляет во вложении файлы ostatki.txt и pusto.txt, также тексты добавляются из файлов в тело письма, , при условии что в данных файлах содержится текст, если файлы пустые, не содержат текст, то письмо не отправляется.
Также в данной функции должна проводиться проверка на отправку почты, если по причине технической ошибки отправка не произошла выводится текст на экран: Ошибка, почта не была отправлена. В случае успеха- на экран выводится: Почта с нулевыми остатками отправлена.
Если лог файлы ostatki.txt и pusto.txt пустые- выводится - Ничего не изменилось, поэтому письмо не отправлено. Также проследи чтобы не было проблем с кодировкой при отправке писем, чтобы заголовки и сам текст был в одной кодировке. Также учти чтобы при чтении файла prices.csv не было проблем с кодировкой ( текст внутри этого файла prices.csv в кодировке windows-1251), следует при записи в базу данных и обработке делать преобразование в utf-8 текстовых данных.
В коде должна быть определена только одна функция maillogfile, всё остальное описанное в задании нужно делать строго по моему описанию выше, не создавая для этого специальных функций.
Также проверь время выполнения файла и выведи в конце подробную информацию- сколько времени было выполнение файла.
А вот такой вышел код: ( реально рабочий- через Cron на хостинге запускаю каждые полчаса- но как говорится и в этом есть нюансы)- но в итоге работает.
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
function maillogfile($to, $from, $fromName, $smtpSettings) {
require 'PHPMailer/src/PHPMailer.php';
require 'PHPMailer/src/SMTP.php';
require 'PHPMailer/src/Exception.php';
$mail = new PHPMailer\PHPMailer\PHPMailer();
$mail->Host = $smtpSettings['smtp_host'];
$mail->SMTPAuth = $smtpSettings['smtp_auth'];
$mail->Username = $smtpSettings['smtp_username'];
$mail->Password = $smtpSettings['smtp_password'];
$mail->SMTPSecure = $smtpSettings['smtp_secure'];
$mail->Port = $smtpSettings['smtp_port'];
$mail->CharSet = 'UTF-8';
$mail->setFrom($from, $fromName);
$mail->Subject = 'Остатки товаров';
$ostatkiContent = file_get_contents('ostatki.txt');
$pustoContent = file_get_contents('pusto.txt');
if (empty($ostatkiContent) && empty($pustoContent)) {
echo "Ничего не изменилось, поэтому письмо не отправлено.";
if (!empty($ostatkiContent)) {
$mail->addAttachment('ostatki.txt');
$mail->Body .= $ostatkiContent;
if (!empty($pustoContent)) {
$mail->addAttachment('pusto.txt');
$mail->Body .= $pustoContent;
echo 'Ошибка, почта не была отправлена.';
echo 'Mailer Error: ' . $mail->ErrorInfo;
echo 'Почта с нулевыми остатками отправлена.';
$startTime = microtime(true);
$ostatkiFile = 'ostatki.txt';
$pustoFile = 'pusto.txt';
$emailFile = 'email.txt';
$emailConfigFile = 'email.cfg';
if (!file_exists($ostatkiFile)) {
file_put_contents($ostatkiFile, '');
file_put_contents($ostatkiFile, '');
if (!file_exists($pustoFile)) {
file_put_contents($pustoFile, '');
file_put_contents($pustoFile, '');
if (!file_exists($dbFile)) {
$db = new SQLite3($dbFile);
$db->exec("CREATE TABLE ostatki (artikul INTEGER, tovar TEXT, qty INTEGER)");
$db->exec("CREATE TABLE pusto (artikul INTEGER, tovar TEXT, qty TEXT)");
$db->exec("CREATE INDEX idx_ostatki_artikul ON ostatki (artikul)");
$db->exec("CREATE INDEX idx_pusto_artikul ON pusto (artikul)");
$insertOstatki = $db->prepare("INSERT INTO ostatki (artikul, tovar, qty) VALUES (:artikul, :tovar, :qty)");
$insertPusto = $db->prepare("INSERT INTO pusto (artikul, tovar, qty) VALUES (:artikul, :tovar, 'zero')");
if (($handle = fopen($csvFile, "r")) !== FALSE) {
fgetcsv($handle, 0, ";"); // Skip header
while (($data = fgetcsv($handle, 0, ";")) !== FALSE) {
$db->exec("BEGIN TRANSACTION");
foreach ($csvData as $data) {
$tovar = mb_convert_encoding($data[2], 'UTF-8', 'Windows-1251');
$insertOstatki->bindValue(':artikul', $artikul, SQLITE3_INTEGER);
$insertOstatki->bindValue(':tovar', $tovar, SQLITE3_TEXT);
$insertOstatki->bindValue(':qty', $qty, SQLITE3_INTEGER);
$insertOstatki->execute();
$insertPusto->bindValue(':artikul', $artikul, SQLITE3_INTEGER);
$insertPusto->bindValue(':tovar', $tovar, SQLITE3_TEXT);
$result = $db->query("SELECT * FROM ostatki WHERE qty = 0");
while ($row = $result->fetchArray()) {
$ostatkiBuffer .= "Товар {$row['artikul']} {$row['tovar']} закончился, проверьте остатки!\n";
$result = $db->query("SELECT * FROM pusto");
while ($row = $result->fetchArray()) {
$pustoBuffer .= "Товар {$row['artikul']} {$row['tovar']} не был заведён по каким-то причинам.\n";
file_put_contents($ostatkiFile, $ostatkiBuffer);
file_put_contents($pustoFile, $pustoBuffer);
$email = file_get_contents($emailFile);
$emailConfig = json_decode(file_get_contents($emailConfigFile), true);
maillogfile($email, $emailConfig['smtp_username'], $emailConfig['Name'], $emailConfig);
$db = new SQLite3($dbFile);
$updateOstatki = $db->prepare("UPDATE ostatki SET qty = :qty WHERE artikul = :artikul");
$insertOstatki = $db->prepare("INSERT INTO ostatki (artikul, tovar, qty) VALUES (:artikul, :tovar, :qty)");
$deletePusto = $db->prepare("DELETE FROM pusto WHERE artikul = :artikul");
$insertPusto = $db->prepare("INSERT INTO pusto (artikul, tovar, qty) VALUES (:artikul, :tovar, 'zero')");
if (($handle = fopen($csvFile, "r")) !== FALSE) {
fgetcsv($handle, 0, ";"); // Skip header
while (($data = fgetcsv($handle, 0, ";")) !== FALSE) {
$db->exec("BEGIN TRANSACTION");
foreach ($csvData as $data) {
$tovar = mb_convert_encoding($data[2], 'UTF-8', 'Windows-1251');
$result = $db->querySingle("SELECT qty FROM ostatki WHERE artikul = '$artikul'", true);
if ($result['qty'] != $qty) {
$updateOstatki->bindValue(':qty', $qty, SQLITE3_INTEGER);
$updateOstatki->bindValue(':artikul', $artikul, SQLITE3_INTEGER);
$updateOstatki->execute();
if ($qty == 0 && $result['qty'] > 0) {
$ostatkiBuffer .= "Товар {$artikul} {$tovar} закончился, проверьте остатки!\n";
$insertOstatki->bindValue(':artikul', $artikul, SQLITE3_INTEGER);
$insertOstatki->bindValue(':tovar', $tovar, SQLITE3_TEXT);
$insertOstatki->bindValue(':qty', $qty, SQLITE3_INTEGER);
$insertOstatki->execute();
$ostatkiBuffer .= "Добавлен товар {$artikul} {$tovar} с остатком {$qty}.\n";
$deletePusto->bindValue(':artikul', $artikul, SQLITE3_INTEGER);
$result = $db->querySingle("SELECT qty FROM pusto WHERE artikul = '$artikul'", true);
$insertPusto->bindValue(':artikul', $artikul, SQLITE3_INTEGER);
$insertPusto->bindValue(':tovar', $tovar, SQLITE3_TEXT);
file_put_contents($ostatkiFile, $ostatkiBuffer);
file_put_contents($pustoFile, $pustoBuffer);
$email = file_get_contents($emailFile);
$emailConfig = json_decode(file_get_contents($emailConfigFile), true);
maillogfile($email, $emailConfig['smtp_username'], $emailConfig['Name'], $emailConfig);
$endTime = microtime(true);
$executionTime = $endTime - $startTime;
echo "Время выполнения скрипта: " . round($executionTime, 2) . " секунд";
Сам бы я такое на написал даже после обучение в полгода-год как мне кажется.. по сути тут работы с нейросетью мне на полдня ( хотя в итоге было три попытки- часа по два каждый раз)
Еще стоит учесть что и тех.задание переписывал ( это уже вторая версия глобально). В первый раз почти все получилось- но что-то пошло не так..и на второй день уже снова делал с нуля..и новое тех.задание ( другими словами). Первые запуски были тормозные- секунд по 20.. было переформулировано- сделай быстрей... Нейросеть давала советы- как сделать лучше- переписывала код.. В итоге обработка файла где 1000 товаров- происходит примерно за секунду.
Так то можно даже чему-то научиться если читать советы:-)
Вот и смотрите теперь- как вам такое? Может ли быть полезно? Всякие обработки эксель файлов на ура с кучей условий ( мне практические такое требуется). В итоге конечно на практических примерах лучше тренироваться- тогда можно научиться чему-то.. а если теоретически- даже и не знаю что у этого железного мозга спрашивать:-)
Были нюансы- на хостинге через планировщик не запускалось- были ошибки- спросил в чем дело- оно тоже дало совет, варианты из-за чего могла быть проблема.. так что пользы много))