Способы написать действительно надежный код в 1Сv7.7




Принцип обмена данными из 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='\

50 Comments

  1. venger

    Это по мотивам прочтения 2-5 глав описания языка:-)

    Reply
  2. artbear

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

    .

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

    Reply
  3. Vitek

    По поводу первой части:

    http://www.kb.mista.ru/article.php?id=175

    Reply
  4. Vitek

    А так, плюс, идея хорошая.

    Reply
  5. vasilykushnir

    (2) А еще:

    — писать толковые комментарии

    — обязательно писать в среде 1С (кода делфи 1с не понимает)

    — и наконец — писать программы так, чтобы они работали.

    Но шутки в сторону:

    1. «А вот если не иметь привычки явно объявлять, а только определять присвоением, то в таком случае, при интерпретации Вам интерпретатор выдаст ошибку: «Переменная не определена (ИмяПеременной)», что позволит отловить такие вещи еще на этапе компиляции.»

    — очень и очень спорная технология. Ловить свои же сознательно встроенные в код ошибки? Я дико извиняюсь…

    2. «Стоит использовать в именах переменных префиксы, указывающие на признак «глобальности» переменной и тип данных»

    Этим пользуюсь. Даже больше: функциям и процедурам имена даю по такому же принципу:

    ПриОткрытии () — локальная

    глОбработкаВизуальности () — в глобальном модуле

    дгм1ПарсерСЗ () — в дополнительном глобальном модуле №1

    и т.д.

    Reply
  6. vinsentfire

    Мне как начинающему осваивать 1С — это действительно очень важные вещи. Это как при начале строительства — как заложен фундамент, так дальше и будет идти строительство. Тут тоже самое. Одним словом — спасибо. Тем более, что и много специалистов делятся своим опытом, тоже можно многое чего узнать и избежать в дальнейшем ошибок.

    Reply
  7. coder1cv8

    Никогда не объявляю переменные в начале процедуры/функции… ) Только по мере необходимости.

    Reply
  8. artbear

    (7) Ага, нужно как в С++ — объявлять/инициализировать по мере необходимости.

    Это намного более надежно.

    Reply
  9. Abadonna

    (5) Вась, твоя привычка объявлять по делу и не по делу ВСЕ функции и процедуры форвардом — ваще зубная боль 🙁 И не лень тебе 😉

    Reply
  10. Abadonna

    +(9) Не фиг вообще в 1С объявлять переменные, кроме тех случаев, когда они являются принимающими, например

    ТекущееВремя(Час, МИнут, Сек) — тут уж никуда не денешься

    Reply
  11. venger

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

    Reply
  12. venger

    +(11) Ну и не паришся с порядком вызова. Это про глобальный модуль в основном я говорю.

    Reply
  13. venger

    Кстати, по поводу префиксов в именах функций и процедур, можно еще в префиксах задавать принадлежность к «классу», т.е., например, все функции и процедуры для работы с Excel через Ole в глоб. модуле, могут начинаться с префикса гл_xlsole, префикс в данном случае просто пример, можно получше придумать.

    Reply
  14. venger

    +(13) Главное в этом деле однообразие и последовательность в применении.

    Reply
  15. Abadonna

    Вот пример на мой взгляд совершенно ничем не оправданного объявления переменных внутри процедуры, ктр. строит конструктор запросов в 7-ке:

    Перем Запрос, ТекстЗапроса, Таб;

    Ну и толку от этого объявления?

    Reply
  16. CheBurator

    (15) толк имхо есть — по «заголовку» процедуры и объявлениям переменных я уже пойму про что речь…

    ..

    было бы хорошо, если бы автор систематизировал вопросы именования переменных…

    у мну например последнее время в этом смысле разброд какой-то…

    Reply
  17. venger

    (15) На то он и конструктор. Кстати, а прикиньте лет так через 100, создадут исскуственный интеллект, который ведь сможет программировать. И будем мы наблюдать процесс программирования, как сейчас на подобии, когда два компа между собой в шахматы играют:-)

    Reply
  18. venger

    +(17) Хотя это уже будет саморазвитие и самосовершенствование компа, так он и до медитации может дойти:-)

    Reply
  19. venger

    +(17) Хотя до медитации, по-моему, уже дошел, вспомните Win98, зависания всякие и т.п.:-)

    Reply
  20. Abadonna

    (16) Смотри код от Камина. Там четко описаны переменные с префиксами типа л_МряПеременная и что префиксы означают.

    Reply
  21. venger

    (16) Так можно писать в начале процедуры или функции, например:

    зпрПоСкладу=СоздатьОбъект(«Запрос»); стрЗапроса=»»; табВывод=СоздатьОбъект(«Таблица»);

    И все видно…

    Reply
  22. venger

    (20) А что за код от Камина?

    Reply
  23. Vitek

    Ссылку из 3 никто я так понимаю и не посмотрел 🙁

    Reply
  24. Abadonna

    А это самая что ни на есть суперская прога по расчету зарплаты на базе 7.7 рядом с которой ЗиК и делать не фиг

    Reply
  25. venger

    (23) Я просто отложил на вечер почитать, но почитаю непременно. Спасибо.

    Reply
  26. venger

    (24) Это про Камина? А эту прогу можно посмотреть?

    Reply
  27. artbear

    (15)Цитата:

    >>Вот пример на мой взгляд совершенно ничем не оправданного объявления переменных внутри процедуры, ктр. строит конструктор запросов в 7-ке:

    >>Перем Запрос, ТекстЗапроса, Таб;

    >>Ну и толку от этого объявления?

    Для конструктора толк есть.

    В этом случае тот текст, который он вставляет, 100% независим от остальных переменных модуля и ГМ, и не влияет на переменные модуля и ГМ.

    Например, в модуле может быть переменная модуля ТекстЗапроса и т.д.

    Reply
  28. Abadonna

    (27) С точки зрения Конструктора — согласен:))) Тем более я сам по образованию инженер-конструктор;)

    Reply
  29. WiseSnake

    (24) Абсолютно не согласен с Вами. Многие отказываются от Камина, слишком геморно там Все сделано. Хотя ЗиК тоже сложна для понимания пользователями, но работает и успешно… в отличии от камина… Ну и обслуживание….

    Reply
  30. CheBurator

    Как пример, ваял отчет сегодня для древней конфы, в отчете юзаю множественный фильтр (из штатного ТиСа) — временно пришлось В МОДУЛЬ отчета передрать из ТиСа процедуры и функции и ГМ ТиСа — не работаю!!! Потому как на форме лежит ТаблицаМФ, а в процедуре, которая раньше была в ГМ выглядит вот так:

    Процедура ЧтоТоДляМФ(Конт)

    ТаблицаМФ = Конт.таблицаМФ;

    в итоге имеем ошибку…

    ..а вот так

    Процедура ЧтоТоДляМФ(Конт)

    Перем ТаблицаМФ;

    ТаблицаМФ = Конт.ТаблицаМФ;

    — не ругается!!

    Reply
  31. alexqc

    Я категорически 🙂 не согласен с тем что НЕ следует объявлять переменные в ф-циях. Наоборот, все локальные переменные НУЖНО объявлять! Сам бы так делал, да вот лень, лень (вот если б была допустима конструкция вида "Перем а=1+2;" в любом месте)… Поскольку в таком случае локальные переменные не пересекаются с переменными вышестоящего уровня (текущего модуля, текущего контекста и ГМ). В этом смысле мне кстати больше подход в PHP нравится: все переменные — локальные, а хочешь до глобальной достучаться — объявляй ее global явно.

    Кстати, говорите интерпретатор ругнется? Попробуйте это

    Код
    Процедура ГдеТутРугань()
    А=А+1;
    КонецПроцедуры;
    

    Показать полностью

    По поводу префиксов — вешь конечно нужная, но злоупотреблять ими также не следует. Достаточно когда префикс отражает НАЗНАЧЕНИЕ переменной, а не тип.

    Для себя я выработал примерно такую систему: то что в ГМ — всегда "гл". Флаги имеют префикс "ф", списки — "спис", таблицы значений — "тз". Строковые представления каких-либо значений — "стр", и т.п. Переменные в "локальной части" алгоритма (например, промежуточные результаты, вобщем то что будет использовано пределах ближайших нескольких строчек) — префикс "т". НО: все эти префиксы (коме префиксов "места" — "гл", "т") — диктуются не типом переменной, а необходимостью алгоритма. То есть, грубо говоря, если у меня есть строка, показывающая адрес, и строка, показывающая представление клиента — то в первом случае переменная скорее всего так и будет "Адрес", а во втором — "стрКлиент". И ИМХО, уж совсем изврат — префиксы перед числами. Вот только посмотрите: чслСумма=чслЦена*чслКоличество. Неужели красиво?

    При этом, как ни странно, иногда и

    Reply
  32. alexqc

    ** что-то сбилось, продолжу

    иногда создается впечатление, что мои префиксы определяются типом (списКлиенты, стрКлиент, зпрКлиент). Но это не так — они определяются именно значением для алгоритма (а тип просто является «следствием» этого значения).

    Reply
  33. venger

    (31) > …если б была допустима конструкция вида "Перем а=1+2;" в любом месте

    Ну, если б…

    > Поскольку в таком случае локальные переменные не пересекаются с переменными вышестоящего уровня (текущего модуля, текущего контекста и ГМ)

    Префиксы исключают вазможность такого пересечения.

    > Кстати, говорите интерпретатор ругнется? Попробуйте это

    > Процедура ГдеТутРугань()

    > А=А+1;

    > КонецПроцедуры;

    Прямо в блоге и говорю, что:

    ———————————————-

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

    Код
    чслПер= чслПер+1; // Переменная не увеличится на 1, она останется пустой

    Показать полностью

    Но, если в начале функции Вы будете иметь привычку присваивать начальные значения переменным, то Вы напишете:

    Код
    чслПер=0;
    //
    // Операторы процедуры или функции
    //
    чслПер= чслПер+1;

    Показать полностью

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

    ———————————————-

    И что?

    > По поводу префиксов — вешь конечно нужная, но злоупотреблять ими также не следует. Достаточно когда префикс отражает НАЗНАЧЕНИЕ переменной, а не тип.

    Назначение можно передать и именем, но в принципе в 1С большинство перфиксов будут отражать тип (в общем случае я считаю, что "ф" — это тот же тип в каком-то смысле). Да и проще тогда ориентироваться, что это, особенно в чужом коде.

    Reply
  34. maljaev

    Мне не понравилось предложение прописывать в начале каждой переменной ее тип. Это сильно затруднит работу с телепатом, так как при наборе имени переменной он ищет ее по начальным символам. Соответственно вместо того чтобы вывалить список наиболее вероятных переменных через 2-3 введенных символа, я буду вынужден каждый раз вводить уже 5-6 символов, и хорошо еще если я помню тип переменной. Лучше уж тип переменной дописывать в конце, тогда при тех же достоинствах не будет описанных неудобств.

    Reply
  35. CheBurator

    (34) я тоже так думал.. фиг там.. телепат ищет по последовательности в любом месте!

    Reply
  36. Shagan

    to 35 -Это дааааа.

    Reply
  37. maljaev

    (35) Я не знаю, какой там у тебя телепат стоит, лично у меня версии «t» и ни хрена подобного не происходит. Проверьте: в конфигураторе создаете пустую обработку, в модуле «сформировать» пишете:

    датНачалоПериода=»»;

    датКонецПериода=»»;

    Если на…

    И что вам телепат вывалит? Лично у меня в списке телепата отсутствует «датНачалоПериода», когда начинаешь набирать с «да» — присутствует.

    Reply
  38. Cifer

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

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

    Reply
  39. venger

    (38) А про общепринятые правила написания кода 1С можно поподробней?

    Reply
  40. Душелов

    (39) по-моему на ИТС-е было где-то…

    Reply
  41. Cifer

    ИТС -> 1С:Предприятие. Работаем с программами -> 1С. Система стандартов и методик разработки конфигураций для платформы 1С:Предприятие 8

    Reply
  42. nickVZ

    датНачалоПериода…

    чслСумма….

    стрАдресПрописки….

    Не назвать ли нам кошку «Кошкой»?@стиш детский

    Reply
  43. maljaev

    (42) Ну да, иногда получается масло масляное… Но если уж вводить такую систему именования, то исключений быть не должно.

    Reply
  44. venger

    (42) В меру, в меру и там, где есть смысл:-)

    Reply
  45. venger

    (42) Просто в условиях когда среда не может сказать мне тип переменной во время программирования, особенно с чужим кодом это не удобно, когда работаешь, а и еще за меня проверять на соответствия типам переменные, то вполне даже стоит…

    Reply
  46. Abadonna

    (22)>А что за код от Камина?

    Во! Нашел у себя систему обозначения переменных от Камина

    // Система префиксов для именования объектов от фирмы КАМИН

    // Гл_ — глобальная переменная, процедура или функция. Описана

    // в глобальном модуле с ключевым словом ЭКСПОРТ.

    // м_ — переменная, описанная явно или неявно в текущем программном модуле.

    // л_ — переменная, описанная явно или неявно в текущей процедуре или функции.

    // п_ — параметр текущей процедуры или функции.

    // рд_ — реквизит диалога. Описан в форме диалога.

    Reply
  47. ADirks

    И опять Джоэл Спольски: статья «Making Wrong Code Look Wrong»

    http://www.joelonsoftware.com/articles/Wrong.html

    По английски, но очень поучительно

    Reply
  48. venger

    Есть переводы многих его блогов и на русском:

    http://local.joelonsoftware.com/mediawiki/index.php/Russian

    Это Вам не fixin:-))))

    Reply
  49. CheBurator

    рд_ — мало!

    я типа так

    рНастройка — рамка

    рб — радиобатон

    фл — флажок

    т — текст

    кн — кнопка

    .. и т.д.

    Reply
  50. CheBurator

    (48) спсб за ссылку

    Reply

Leave a Comment

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