Проверка орфографии средствами Yandex Speller




Принцип обмена данными из 1С с сайтом (на MySQL) и выдачи (публикации) этих данных по запросу.
PHP-Скрипт автоматической загрузки данных из файла данных в формате CSV в базу данных сайта работающего на WordPress.

В продолжение моей темы: 1С:Альфа-Авто Автосалон Автосервис: обмен с сайтом.
С помощью данного скрипта можно загружать в автоматическом режиме, по расписанию, данные сервисных книжек (ремонтов авто) из 1С:Альфа-Авто Автосалон Автосервис.
Также можно загружать данные в ручном режиме: для этого делается скрытая страница, где размещается специальная кнопка.
Комментарии размещенные внутри скрипта разъяснят логику и порядок действия.
Комментарии с "/////    echo" использовались для отладки.
Дополнительно создана таблица для журналирования результатов загрузки данных.
Скрипт включает в себя защиту от SQL инъекций (думаю безопасность соблюдена в полной мере).
В кратце:
1. Пишется скрипт, который запускает этот.
2. Создается регламентное задание в WordPress, по которому запускается скрипт из п.1. 
3. Этот скрипт осуществляет проверку на существование файла обмена в папке.
4. Если данные не новые, загрузка не производится.
5. Если данные новые, очищается таблица сервисных книжек.
6. Загружаются новые данные.

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

<?php // Полная загрузка сервисных книжек, создан 2024-01-05 12:44:55

global $wpdb2;
global $failure;
global $file_hist;

/////  echo '<H2><b>Старт загрузки</b></H2><br>';

$failure=FALSE;
//подключаемся к базе
$wpdb2 = include_once 'connection.php'; ; // подключаемся к MySQL
// если не удалось подключиться, и нужно оборвать PHP с сообщением об этой ошибке
if (!empty($wpdb2->error))
{
/////   echo '<H2><b>Ошибка подключения к БД, завершение.</b></H2><br>';
$failure=TRUE;
wp_die( $wpdb2->error );
}

$m_size_file=0;
$m_mtime_file=0;
$m_comment='';
/////проверка существования файлов выгрузки из 1С
////файл выгрузки сервисных книжек
$file_hist = ABSPATH.'/_1c_alfa_exchange/AA_hist.csv';
if (!file_exists($file_hist))
{
/////   echo '<H2><b>Файл обмена с сервисными книжками не существует.</b></H2><br>';
$m_comment='Файл обмена с сервисными книжками не существует';
$failure=TRUE;
}

/////инициируем таблицу лога
/////если не существует файла то возврат и ничего не делаем
if ($failure){
///включает защиту от SQL инъекций и данные можно передавать как есть, например: $_GET['foo']
/////   echo '<H2><b>Попытка вставить запись в лог таблицу</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>$m_mtime_file,'last_size_upload'=>$m_size_file,'comment'=>$m_comment));
wp_die();
/////    echo '<H2><b>Возврат в начало.</b></H2><br>';
return $failure;
}
/////проверка лога загрузки, что бы не загружать тоже самое
$masiv_data_file=stat($file_hist);   ////передаем в массив свойство файла
$m_size_file=$masiv_data_file[7];    ////получаем размер файла
$m_mtime_file=$masiv_data_file[9];   ////получаем дату модификации файла
////создаем запрос на получение последней удачной загрузки
////выбираем по штампу времени создания (редактирования) файла загрузки AA_hist.csv, $m_mtime_file

/////   echo '<H2><b>Размер файла: '.$m_size_file.'</b></H2><br>';
/////   echo '<H2><b>Штамп времени файла: '.$m_mtime_file.'</b></H2><br>';
/////   echo '<H2><b>Формирование запроса на выборку из лога</b></H2><br>';
////препарируем запрос
$text_zaprosa=$wpdb2->prepare("SELECT * FROM `vin_logs` WHERE `last_mtime_upload` = %s", $m_mtime_file);
$results=$wpdb2->get_results($text_zaprosa);

if ($results)
{   foreach ( $results as $r)
{
////если штамп времени и размер файла совпадают, возврат
if (($r->last_mtime_upload==$m_mtime_file) && ($r->last_size_upload==$m_size_file))
{////echo '<H2><b>Возврат в начало, т.к. найдена запись в логе.</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>$m_mtime_file,'last_size_upload'=>$m_size_file,'comment'=>'Загрузка отменена, новых данных нет, т.к. найдена запись в логе.'));
wp_die();
return $failure;
}
}
}
////если данные новые, пишем в лог запись о начале загрузки
/////echo '<H2><b>Попытка вставить запись о начале загрузки в лог таблицу</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>0, 'last_size_upload'=>$m_size_file, 'comment'=>'Начало загрузки'));

////очищаем таблицу
$clear_tbl_zap=$wpdb2->prepare("TRUNCATE TABLE %s", 'vin_history');
$clear_tbl_zap_repl=str_replace("'","`",$clear_tbl_zap);
$results=$wpdb2->query($clear_tbl_zap_repl);
/////   echo '<H2><b>Очистка таблицы сервисных книжек</b></H2><br>';
if (empty($results))
{
/////   echo '<H2><b>Ошибка очистки таблицы книжек, завершение.</b></H2><br>';
//// если очистка не удалась, возврат
$failure=TRUE;
wp_die();
return $failure;
}

////загружаем данные
$table='vin_history';         // Имя таблицы для импорта
//$file_hist Имя CSV файла, откуда берется информация     // (путь от корня web-сервера)
$delim=';';          // Разделитель полей в CSV файле
$enclosed='"';      // Кавычки для содержимого полей
$escaped='\

38 Comments

  1. spec8s

    Совсем недавно делал нечто подобное, т. к. веб-сервис перестал работать. Только метод чтения XML возможно немного короче:

    ЧтениеXML = Новый ЧтениеXML();
    ЧтениеXML.УстановитьСтроку(HttpОтвет.ПолучитьТелоКакСтроку());
    
    ПостроительDOM = Новый ПостроительDOM;
    ДокументDOM = ПостроительDOM.Прочитать(ЧтениеXML);
    
    РезультатПроверки = Новый Структура(«error», Новый Массив);
    
    ЭлементыError = ДокументDOM.ПолучитьЭлементыПоИмени(«Error»);
    Для Каждого ЭлементError Из ЭлементыError Цикл
    СтруктураОшибок = Новый Структура(«s», Новый Массив);
    Для Каждого АтрибутError Из ЭлементError.Атрибуты Цикл
    СтруктураОшибок.Вставить(АтрибутError.Имя, Число(АтрибутError.Значение));
    КонецЦикла;
    
    ЭлементыWord = ЭлементError.ПолучитьЭлементыПоИмени(«word»);
    СтруктураОшибок.Вставить(«word», ЭлементыWord[0].ТекстовоеСодержимое);
    
    ЭлементыS = ЭлементError.ПолучитьЭлементыПоИмени(«s»);
    Для Каждого ЭлементS Из ЭлементыS Цикл
    СтруктураОшибок.s.Добавить(ЭлементS.ТекстовоеСодержимое);
    КонецЦикла;
    
    Если СтруктураОшибок.s.Количество() > 0 Тогда
    РезультатПроверки.error.Добавить(СтруктураОшибок);
    КонецЕсли;
    КонецЦикла;
    

    Показать

    Reply
  2. 🅵🅾️🆇

    (1) завтра подробнее посмотрю, идея была сделать покрасивее, разобрав XML через DOM, но немног не сдюжил)

    Код вышел бы примерно той же длины, отличие в том, что данные в массив Я засовываю под русифицированными читабельными переменными, хотя этот момент можно было решить и изящнее, на вскидку записать в строку с разделителями «Атрибут:РускийСиноним:ОжидаемыйТипДанных; … : … : … ; …».

    Привычка, если работаю с 1с — переменные должны быть русскими и PascalCase (исключение для массивов и некоторых данных, там могу поставить префикс), а вот в JS, Python, C++ и тд уже ожидаю увидеть латинские camelCase.

    Но спасибо за поправку, скорее всего переделаю эту часть.

    Reply
  3. nasonkin

    Самый простейший вариант — отображение слов с ошибками, делал через SOAP. Вдруг кому пригодиться:

    WSОпределение = Новый WSОпределения(«http://speller.yandex.net/services/spellservice?WSDL»,»»,»»,,10);
    WSПрокси  = Новый WSПрокси(WSОпределение,»http://speller.yandex.net/services/spellservice»,»SpellService»,»SpellServiceSoap»,,10);
    Пакет    = WSПрокси.ФабрикаXDTO.Создать(WSПрокси.ФабрикаXDTO.Тип(«http://speller.yandex.net/services/spellservice»,»CheckTextRequest»));
    Пакет.options   = 55;
    Пакет.format = «plain»;
    Пакет.lang  = «ru»;
    Пакет.text  = Текст;
    РезультатВебОперации = WSПрокси.checkTexts(Пакет);
    Для каждого ГрамОшибка из РезультатВебОперации.ArrayOfSpellResult.SpellResult[0].error Цикл
    СловаСОшибками = Строка(СловаСОшибками)+»‘»+Строка(ГрамОшибка.word)+»‘, »
    КонецЦикла
    Возврат Лев(СловаСОшибками,СтрДлина(СловаСОшибками)-2)
    

    Показать

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

    Reply
  4. 🅵🅾️🆇

    (3) Я тоже через него делал изначально. Вчера был доступен «checkText», но с ограничением: передавать параметром надо было только текст.

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

    Вот так работает:

    Определения = Новый WSОпределения(«http://speller.yandex.net/services/spellservice?WSDL»,,,Неопределено,300);
    Прокси  = Новый WSПрокси(Определения, «http://speller.yandex.net/services/spellservice»,
    «SpellService», «SpellServiceSoap», Неопределено, 300);
    Данные  = Прокси.checkText(Текст);
    

    Для меня это не очень важный момент, так через GET также отлично работает.

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

    Пытаться достучаться в цикле и вот это все.

    Вполне достаточно:

    URL    = СтрШаблон(«services/spellservice/checkText?text=%1&lang=%2&options=%3&format=%4», Текст, Язык, Опции, Формат);
    HTTPСоединение = Новый HTTPСоединение(«speller.yandex.net», 80, , , , 300);
    HTTPЗапрос  = Новый HTTPЗапрос(URL);
    HTTPОтвет  = HTTPСоединение.Получить(HTTPЗапрос);
    
    Reply
  5. guy_septimiy

    Интересное решение.

    Респект.

    Reply
  6. &rew

    У меня одного было ощущение, когда я на звезду нажал, как будто «зигу» кинул?

    Reply
  7. 🅵🅾️🆇

    (6) Полно вам, думаю эмблемка Grammar Nazi никого не оскорбит тк узнаваема и к томуже вполне уместна)

    Reply
  8. apostal86

    А api нет у этого Yandex Speller?

    Reply
  9. RailMen

    (6) у меня тоже!

    Reply
  10. 🅵🅾️🆇

    (8) Не совсем понял вопрос.

    Обработка и использует API Яндекса, дружит с ним через HTTP GET (в коде есть закоменченный кусочек для общения через веб сервисы, но там не выйдет вместе с текстом передавать параметры).

    По сути обработка является оберткой над API Яндекса.

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

    Я, наверное, слишком сложно и муторно объясняю, лучше посмотрите примеры использования в теме, там все намного проще и лаконичнее.

    Reply
  11. KroVladS

    Плагин для конфигуратора сделаете?

    Reply
  12. 🅵🅾️🆇

    (11) Плагин?

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

    Также есть «графит», но о нем ни слуху ни духу уже несколько лет. Может Я чего проспал?)

    Или вы о «расширения конфигурации», штуке которая ставиться поверх типовых не снимая с поддержки?

    Если о ней, то Я плохо представляю, что такого особенного Я могу сделать, кроме как добавить саму обработку.

    Если кому не достаточно примеров вызовов из темы — могу добавить тестовую конфигурацию.

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

    Reply
  13. apostal86

    (10) Спасибо за ответ

    Reply
  14. Поручик

    На вскидку должна запуститься на чем угодно, начиная с 8.3.6.1977 с отключенным режимом совместимости

    Reply
  15. 🅵🅾️🆇

    (14)

    с отключенным режимом совместимости

    Если это так важно, добавлю)

    Reply
  16. Поручик

    (15) Конечно важно. Полно конф, которые работают на 8.3.7.ХХХХ и выше, но внутри у них 8.3.5 или даже 8.2.

    Reply
  17. 🅵🅾️🆇

    (16) Я думал это очивидно, но пусть будет.

    Да и не велика проблема, вполне можно переписать эти моменты при помощи строковых функций из БСП.

    Reply
  18. Davurov

    Спасибо большое! Очень классная штука! Не подскажите как сделать полосу прокрутки в поле HTML? Когда длинное предложение неудобно с ним работать так как строчки не переносятся сами и нет полосы прокрутки

    Reply
  19. 🅵🅾️🆇

    (18) А, извиняюсь. Делал под себя и не ожидал полосы прокрутки, поэтому для красоты специально спрятал. В модуле формы, в процедуре «СобратьHTML()» сотрите «overflow: hidden;».

    Если у вас выходит в ширину слишком длинной строка, то советую посмотреть на следующие стили CSS (также добавлять в СобратьHTML() в <st yle></style> блок):

    pre {
    white-space: pre-line;
    word-wrap: break-word;
    word-break: break-all;
    width: 100%;
    }
    

    Сейчас создам в темке блок с QA и добавлю туда ответы на вопросы.

    Удачи)

    Reply
  20. Davurov

    (19)

    overflow

    Ооо! спасибо заработало ) И ещё вопрос, если используется ОбработкаОповещения «ПослеПроверкиОрфографии», то для случая когда нет ошибок и стоит «ЗакрытьЕслиБезОшибок», после закрытия формы в эту процедуру не попадает, поэтому не могу вывести сообщение пользователю: «Все ок. ошибок нет =)»

    Форма закрывается с этой ветки:

    Если БезОшибок И ЗакрытьЕслиБезОшибок Тогда
    ЭтаФорма.Закрыть(Новый Структура(«Текст,БезОшибок,КоличествоОшибок»,Текст,БезОшибок,КоличествоОшибок));
    Возврат;
    КонецЕсли; // Если БезОшибок И ЗакрытьЕслиБезОшибок
    Reply
  21. 🅵🅾️🆇

    (20) На примере примера из темы для немодального вызова:

    &НаКлиенте
    Процедура ПроверитьОрфографию(Команда)
    //СтрокаНаПроверку = «Мамо мыла раму.»;
    Оповещение   = Новый ОписаниеОповещения(«ПослеПроверкиОрфографии», ЭтаФорма, СтрокаНаПроверку);
    П     = Новый Структура(«Текст,Язык,Формат,МинДлинаСлова,Словарь,Опции,ЗакрытьЕслиБезОшибок»,
    СтрокаНаПроверку, «ru,en», «plain», 0, «», 31, Истина);
    Форма = ОткрытьФорму(«Обработка.ПроверкаОрфографии.Форма», П, ЭтаФорма, Истина, , , Оповещение);
    Если Форма = Неопределено Тогда
    Сообщение = Новый СообщениеПользователю;
    Сообщение.Текст = «Форма не была создана, вероятно ошибок нету.»;
    Сообщение.Сообщить();
    КонецЕсли; // Если Форма = Неопределено
    КонецПроцедуры // ПроверитьОрфографию()
    

    Показать

    Ну или если не возражаете против модальных окон ( лично мое руководство их очень любит :3 ), то там все еще проще, просто смотрите, что возвращает:

    Результат = ОткрытьФормуМодально(«Обработка.ПроверкаОрфографии.Форма», Новый Структура(«Текст», СтрокаНаПроверку), ЭтаФорма);
    
    Reply
  22. Davurov

    Ок спасибо большое! очень выручили!

    P.S у меня все равно приходит форма, поэтому добавил условие

    Если Форма = Неопределено ИЛИ Форма.БезОшибок Тогда
    Сообщение    = Новый СообщениеПользователю;
    Сообщение.Текст    = «Ошибок нет!»;
    Сообщение.Сообщить();
    КонецЕсли; // Если Форма = Неопределено
    Reply
  23. Davurov

    Не не не, спасибо =) никаких модальностей =)

    Reply
  24. ra1ich

    Прикольно, для нас будет актуально.

    Reply
  25. KroVladS

    (12)

    Я как раз dll-ку имел ввиду.

    Reply
  26. 🅵🅾️🆇

    (25) Сильно врядли. Следующий раз как буду плюсы открывать — это будет внешняя компонента для распознования текста :3

    Reply
  27. azubar

    У меня не работает. либо вообще яндекс возвращает результат без ошибок либо только первую ошибку, в то время как просто в браузере выдает все ошибки, видео:

    https://www.screencast.com/t/Ym9LeUQokNWy

    Если слать текст на проверку яндексу POSтом то нормально работает.

    И перекодировку текста лучше делать:

    ТекстНаПроверку = КодироватьСтроку(Текст, СпособКодированияСтроки.КодировкаURL);
    
    Reply
  28. 🅵🅾️🆇

    (27) Все работает со строкой:

    ашибка   арфаграфия праверить ашибки

    Обработка внедрена на производстве в несколько документов перед записью.

    С КодироватьСтроку() полностью согласен, добавлю в следующую версию.

    Проблема действительно может иметь место быть, тк GET запрос передает параметры через URL, возможно нечто в тексте «портит» его.

    Reply
  29. Артано
    Производиться десять попыток достучаться до сервиса, прежде чем будет выведено сообщение о невозможности использования (сервис лег, ну или что вероятнее — ваш интернет).

    Хотел пошутить про применение обработки к тексту публикации, но вспомнил, что здесь нужен семантический, а не синтаксический анализ.

    Остальное порадовало, спасибо!

    Reply
  30. vgrichuk

    Оффтопик. Коллеги, меня одного покоробила эмблема граммар-наци, использованная в описании обработки?

    Reply
  31. 🅵🅾️🆇

    (31)

    =:'(#k8SjZc9Dxk . #k8SjZc9Dxk,)’:=

    Reply
  32. 🅵🅾️🆇

    (29) Поправьте, а Я обязательно поправлю в публикации.

    Возможно у меня есть в наличии некоторое косноязычие.

    Спасибо, рад теплым отзывам.

    Reply
  33. Артано

    (33) Ошибка из расстрельного списка грамматических нацистов (их символ в картинке публикации). написание тся и ться. Я думал после древнего апдейта вконтакте, когда разделили лайк на собственно лайк и на репост (мне нравиТся и поделиТЬся).

    Reply
  34. BorovikSV

    а почему логотип стилизован под фашистский флаг?

    Reply
  35. madonov

    (36) это логотип движения «Граммар-наци».

    Обычно символизирует нетерпимость к грамматическим ошибкам и их авторам.

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

    Reply
  36. 🅵🅾️🆇

    (38) Такого не знал.

    Просто показалось, что будет довольно уместным и привлекающим внимание…

    Reply
  37. madonov

    (39) Ну внимание однозначно привлекает =)))

    Reply
  38. Perfolenta

    (39) уберите его, пожалуйста, не надо провоцировать людей… привлекать внимание можно и не использую фашистскую символику…

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *