start_time = date('Y-m-d H:i:s'); $path_arr = [ ['mode' => 1, 'path' => \Yii::getAlias('@auto_upload')], ['mode' => 2, 'path' => \Yii::getAlias('@mail_upload')], ]; $arr_supported_extension = Parser::supportedExtension(); foreach ($arr_supported_extension as $ext) { $this->parseFilesByExtension( $ext , $path_arr ); } } public function actionTest() { Console::output('It is working'); \Yii::info('2', 'parser'); } public function actionSaveMailAttachments() { \Yii::info('Начало сохранения файлов почты', 'mail'); // получим разделитель для файлов поставщика $importer_id_prefix = ImportersFiles::FILES_PREFIX; // подключимся к ящику $mail_reader = new ImapMailReader('{imap.gmail.com:993/imap/ssl/novalidate-cert}', 'tsurkanovm@gmail.com', 'Wtvr@2000'); // 1. получим все вложения \Yii::info('Начало сохранения файлов почты', 'mail'); $files = $this->getMailAttachments($mail_reader, $importer_id_prefix); if (!$files) { // нет файлов в ящиках (не было вложений в письмах) \Yii::warning('Вложений не найдено', 'mail'); return; } // 2. если в вложениях есть архивы - распакуем их и дополним итоговый массив \Yii::info('Запуск распаковки архивов...', 'mail'); $this->UnpackFiles($files); // 3. переименуем, зарегистрируем прайсы и перенесем извлеченные файлы // укажем папку куда нужно перенести все извлеченные вложения \Yii::info('Запуск перемещения и регистрации прайсов...', 'mail'); $new_destination = \Yii::getAlias('@mail_upload') . '/'; $this->registerAndReplaceFiles($files, $new_destination); } protected function parseFilesByExtension( $ext, $path_arr ) { \Yii::info("Начало загрузки файлов прайсов {$ext}", 'parser'); foreach ($path_arr as $path_config) { foreach ( glob( $path_config['path'] . "/*.{$ext}" ) as $file_path ) { $file_name = basename( $file_path, ".{$ext}" ); \Yii::info( "Обработка файла - $file_path", 'parser' ); $config = $this->getParsingConfiguration( $file_name, $path_config['mode'], $ext ); if ($this->parseFile($file_path, $config)) { $temp_file = \Yii::getAlias('@temp_upload') . '/' . $file_name . ".{$ext}"; if( file_exists( $temp_file ) ) unlink($temp_file); \Yii::info("Загрузка файла - $file_path успешно завершена", 'parser'); } else { \Yii::error("Загрузка файла - $file_path завершена с ошибкой", 'parser'); } //при любом завершении скрипта файл с очереди автозагрузки нужно удалить $auto_file = $path_config['path'] . '/' . $file_name . ".{$ext}"; if( file_exists( $auto_file ) ) unlink($auto_file); } } } protected function parseFile($file_path, $configuration) { // регистрация в лог $log_model = new Log(); $log_model->importer_id = $configuration['importer_id']; $log_model->time_start = $this->start_time; $log_model->file_name = $file_path; $mode = $configuration['mode']; unset($configuration['mode']); $log_model->record_type = $mode; $log_msg = ''; $has_error = true; if (!file_exists($file_path)){ $log_msg = "$file_path - файл не найден!"; } else { $parser_config = []; if (isset($configuration['parser_config'])) { $parser_config = $configuration['parser_config']; } $data = \Yii::$app->multiparser->parse($file_path, $parser_config); if (!$data) { $log_msg = "Ошибка обработки файла прайса. Парсер вернул пустой массив"; } else { try { $writer = new PriceWriter(); $writer->setMode($mode); $writer->setConfiguration($configuration); $writer->setData($data); $writer->writePriceToDB(); $has_error = $writer->hasValidationError(); $log_msg = strip_tags( $writer->getValidatedMsg() ); if ( $has_error ) { \Yii::error($log_msg, 'parser'); } else { \Yii::info($log_msg, 'parser'); } } catch (\Exception $e) { $log_msg = $e->getMessage(); } } } $log_model->error = (int) $has_error; $log_model->log_msg = $log_msg; // запишем данные в лог $log_model->save(); return true; } private function getMailAttachments($mail_reader, $importer_id_prefix = '') { // получим все внутренние ящики (по ярлыкам) $mailboxes = $mail_reader->getListMailboxes(); // очистим массив в котором в итоге окажутся все файлы вложений, а также распакованные файлы из архивов $files = []; foreach ($mailboxes as $custom_label) { // получим поставщика исходя из маски ярлыка $importer_id = ImportersFiles::getIdFromMailBox($mail_reader->getHostname(), $custom_label); // читаем письма конкретного ярлыка $mail_reader->reOpen($custom_label); // создадим сейвер вложений для данного ярлыка (ящика) $saver = new MailAttachmentsSaver($mail_reader); // если данный ярлык содержит id поставщика, то все вложения нужно промаркировать (в начало файла добавить id поставщика + разделитель $importer_id_prefix) if ($importer_id) { $saver->setFileNamePrefix($importer_id . $importer_id_prefix); // $importer_id = ''; } // сохраняем вложения if ($saver->saveAttachmentsTo(\Yii::getAlias('@temp_upload'), 'UNSEEN')) { // закидываем вытащенные файлы в наш итоговый массив $files = array_merge($files, $saver->getSavedFilesArr()); } else { // ящик не имеет писем с вложениями continue; } } return $files; } private function UnpackFiles(&$files, $importer_id_prefix = '') { // если в вложениях встречаются архивы - распакуем // иициируем фабрику архиваторов $arch_creator = new ArchiveCreator(); // получим все расширения которые поддерживает фабрика $arch_extensions = $arch_creator->getHandleExtension(); // выбираем только те файлы которые мы можем распаковать $arch_files = array_intersect($files, $arch_extensions); foreach ($arch_files as $arch_name => $arch_ext) { // создаем конкретный архиватор по расширению $arch_reader = $arch_creator->create($arch_name, $arch_ext); // определим ид поставщика по имени файла $importer_id = ImportersFiles::getIdFromFileName($arch_name); if ($importer_id) { // если файл архива содержит поставщика (на предыдущих этапах мы его туда записали) // то нужно все вложенные файлы также промаркировать $arch_reader->setFileNamePrefix($importer_id . $importer_id_prefix); //$importer_id = ''; } // распаковываем файлы $arch_reader->extractTo(\Yii::getAlias('@temp_upload') . '/'); // убираем файл архива из итогового массива unset($files[$arch_name]); // удаляем файл архива unlink($arch_name); // добавляем распакованные файлы к итоговому массиву $files = array_merge($files, $arch_reader->getExtractedFiles()); } } private function registerAndReplaceFiles(&$files, $new_destination) { foreach ($files as $name => $ext) { // имена файлов для расширения csv нужно поменять, // для остальных оставляем оригинальные имена вложений (плюс ид поставщика если письмо от поставщика) $file_name = pathinfo($name, PATHINFO_BASENAME); if ($ext == 'csv') { // определим ид поставщика по имени файла $importer_id = ImportersFiles::getIdFromFileName(basename($name));; // зарегистрируем прайс if ($importer_id) { $files_model = new ImportersFiles(); $files_model->importer_id = $importer_id; if ($files_model->save()) { // имя файла переименуем на id записи $file_name = \Yii::$app->db->getLastInsertID() . '.csv'; } else { $files_model->throwStringErrorException(); } } } if (rename($name, $new_destination . $file_name)) { \Yii::info("Вложение {$name} сохранено", 'mail'); } else { new \ErrorException("Нет возможности переписать файл {$name}"); } } } protected function getParsingConfiguration( $file_name, $mode, $ext ){ if ($ext === 'xml') { $files_model = new ImportersFiles(); // id поставщика всегда = 1 - Склад $files_model->importer_id = 1; try { $files_model->save(); } catch (ErrorException $e) { throw $e; } // получим id только что записанной записи $record_id = $files_model->find() ->where(['importer_id' => $files_model->importer_id]) ->orderBy(['id' => SORT_DESC]) ->one() ->id; $config = ['record_id' => $record_id, 'importer_id' => 1, 'mode' => $mode, 'parser_config' => [ 'mode' => 'console'] ]; } else { $importer_id = ImportersFiles::findOne(['id' => $file_name])->importer_id; $current_importer = Importers::findOne(['id' => $importer_id]); $keys = $current_importer->keys; $mult_array = $current_importer->multiply; // получим настройки ценообразования и передадим их отдельно в конвертер $sign = ''; $multiplier = ''; extract($mult_array); $config = [ 'record_id' => $file_name, 'importer_id' => $importer_id, 'mode' => $mode, 'parser_config' => ['keys' => $keys, 'converter_conf' => ['sign' => $sign, 'multiplier' => $multiplier], 'mode' => 'console'] ]; } return $config; } }