может быть проще получить данные из АД запросом? How to: AD + MSSQL to SSRS mssql умеет и у него нативно есть json Работа с данными JSON - SQL Server 1 запросом можно все получить без циклов
Можно и на комаров охотиться при помощи гаубицы. Но вряд ли нужно. «У нас было 2 админа, 75 рабочих мест, 5 офисов в разных городах, пол-стойки серверов и целое множество интернет-провайдеров всех сортов и расцветок, балансировка каналов, а также почта, ftp, облачная АТС и 2 дюжины софтфонов. Не то чтобы это был необходимый запас для бизнеса, но если начал предоставлять услуги, становится трудно остановиться. Единственное, что вызывало у меня опасение — это облачная АТС. Ничто в мире не бывает более беспомощным, безответственным и порочным, чем sip-софтфоны. Я знал, что рано или поздно мы перейдем и на эту дрянь». Задача — есть некоторое количество IP-софтфонов Acrobits Groundwire. Им нужно получать общий справочник компании. Вариантов аж целых два: либо разворачивать толстожопый сервер CardDAV (99% которых не умеют заполнять адресные книги из LDAP), либо свой собственный Web Service, для которого всего лишь документированы форматы XML и JSON, которые умеет Groundwire. Но зачем нам толстожопые серверы протухших лет 10 назад технологий? У нас ведь уже есть nginx и php (самописный портал для самостоятельного WOL-пробуждения офисных компов удалёнщиками). В php есть модуль ldap. К нему есть масса примеров использования. Чего ещё хотеть?
Вот именно этот момент я и имел ввиду. Добавляете ValueObject'ы по классам (тоже по 1 на файл), разбиваете сплошной блок на классы, делаете точку входа. Вы же спрашивали, как научиться делать хорошо, а не как нравится? Надо еще типы везде добавить, использовать исключения вместо die, читать конфиг из ENV или yaml, вынести работу с HTTP отдельно. Но на все это за нарушением кодстайла сложно смотреть. В этом и дело. Код же не вам принадлежит, а компании. Поэтому надо, чтобы удобно было не вам, а большинству их тех, кто с ним сталкивается. С учетом большой текучки в IT и длительности жизни решений относительно длительности работы среднего сотрудника это необходимо. А еще нужен контейнер какой-либо, если скрипт не одноразовый и на него забьют. Чтобы закрепить версию рантайма. Сейчас не нужно, а через год станет необходимым, т.к. при очередном апдейте чего-то что-то отвалится.
Много чего тут по уму написали, я это даже перечитаю потом чтобы над своим кодом подумать дополнительно Со своей стороны заметил примерно следующее: 1. Если результирующий объект - JSON, ошибки также должны отдавать JSON 2. Висяки вроде PHP: if (условие) { // длиннокод} else { // ругнуться и выйти} по мне очень не ок. Ок - вот так: PHP: if (не-условие) { // ругнуться и выйти}// длиннокод 3. for-цикл тут выглядит жутковато. Возможно, куда правильнее было бы сделать что-то вроде PHP: $array_contacts = array_map(функция_обработки_элемента, $data) $data перед этим, по-видимости, нужно немного причесать, чтобы исключить лишние элементы из обработки. 4. Да, классы тут бы очень не помешали.
Вот кстати что люто бесит в ПХП в последнее время, что вещи вроде PHP: условие || exit; работают, а, например, PHP: условие || return; - нет До ?? додумались, до ?: додумались, казалось бы ещё чуть-чуть - и вообще супер будет. Но что-то нет. Ну или я чего-то не знаю
В данном случае — не должны, выхлоп будет сразу съеден web-клиентом, а в нём не определены ошибки в json. Я немного дополнил, теперь при ошибках возвращается в хидере http 404. Не разворачивать if? Принято. А что не так? Мы набиваем многомерный ассоциативный массив, а потом чохом его вернём json_encode. Сколько вернулось элементов в поиске, говорит элемент 'count' в результате ldap_get_entries. Не надо. Мы знаем точно, какие элементы нам нужны в $ldapdata и выбираем их ещё на этапе ldap_search в $attr. Я убрал лишние атрибуты. Спойлер: Говнокод PHP: <?phpfunction convertBinToMSSQLGuid(string $binguid): string{ $unpacked = unpack('Va/v2b/n2c/Nd', $binguid); return sprintf( '%08X-%04X-%04X-%04X-%04X%08X', $unpacked['a'], $unpacked['b1'], $unpacked['b2'], $unpacked['c1'], $unpacked['c2'], $unpacked['d'] );}$username = 'readldapuser';$password = '########';$server = 'ldap://####.local';$domain = '@####.local';$port = 389;$ldap_connection = ldap_connect($server, $port);if (! $ldap_connection) { header('HTTP/1.0 404 Not Found'); echo '<p>LDAP SERVER CONNECTION FAILED</p>'; exit;}// Help talking to ADldap_set_option($ldap_connection, LDAP_OPT_PROTOCOL_VERSION, 3);ldap_set_option($ldap_connection, LDAP_OPT_REFERRALS, 0);$ldap_bind = @ldap_bind($ldap_connection, $username . $domain, $password);if (! $ldap_bind) { header('HTTP/1.0 404 Not Found'); echo '<p>LDAP BINDING FAILED</p>'; exit;}$base_dn = 'DC=#####,DC=local';$filter = '(&(objectCategory=person)(!(UserAccountControl:1.2.840.113556.1.4.803:=2))(|(ipPhone=*)))';$attr = array('sn', 'givenname', 'displayname', 'objectguid', 'ipPhone');$result = ldap_search($ldap_connection, $base_dn, $filter, $attr);if (! $result) { header('HTTP/1.0 404 Not Found'); echo '<p>LDAP SEARCH FAILED</p>'; exit;}$ldapdata = ldap_get_entries($ldap_connection, $result);if ($ldapdata['count'] == 0) { header('HTTP/1.0 404 Not Found'); echo '<p>No results found!</p>'; exit;}$array_contacts = array(); for ($i = 0; $i < $ldapdata['count']; $i++) { $array_person = array(); $array_person['contactEntries'] = array(array( 'entryId' => 'tel:0', 'label' => 'Внутренний', 'type' => 'tel', 'uri' => ($ldapdata[$i]['ipphone'][0]) )); $array_person['contactId'] = convertBinToMSSQLGuid($ldapdata[$i]['objectguid'][0]); $array_person['countryCode'] = 'ru'; $array_person['displayName'] = $ldapdata[$i]['displayname'][0]; $array_person['fname'] = $ldapdata[$i]['givenname'][0]; $array_person['lname'] = $ldapdata[$i]['sn'][0]; array_push($array_contacts, $array_person);} $json = json_encode(array('contacts' => $array_contacts), JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); header('Content-Type: application/json; charset=utf-8'); header('Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0'); echo $json;
С точки зрения решения задачи - всё ок. С точки зрения получения легкочитаемого кода - не ок. Просто для сравнения PHP: $a = [];for ($i = 0; $i < $ldapdata['count']; $i++) { $a[] = $ldapdata[$i];} против PHP: $a = [];foreach ($ldapdata as $item) { $a[] = $item;} Второй вариант смотрится и читается легче. Меньше кода => добро А в последнее время я вообще стараюсь не использовать циклы, решая задачки как-то так: PHP: $array = array_map(function($item) { return $item }, $data); Такое порой в одну строку позволяет сворачивать блоки, которые при "старом" подходе заняли бы 5-6-10 строк. Особенно хорошо в новом синтаксисе (пхп 7.4+): PHP: $array = array_map(fn($item) => $item, $data); Правда, тут нужно избавиться от лишних элементов вроде $ldapdata['count']: проитерироваться можно и без них, и если их не убрать, они тоже появятся при перечислении. Если говорить про дальнейшую оптимизацию, то данные для подключения можно убрать в отдельный пхп-файл или в какой-нибудь JSON, сократив PHP: $username = 'readldapuser';$password = '########';$server = 'ldap://####.local';$domain = '@####.local';$port = 389; до PHP: $creds = json_decode(file_get_contents( path-to-file.json )) или PHP: $creds = incude(path-to-file.php) или PHP: extract(incude(path-to-file.php)); Хотя последнее на мой взгляд не очень ок, так как не видно, с какими переменными в итоге через него можно будет поработать. Затем (если продолжать оставаться в процедурном подходе) обобщить аварийные завершения в функцию, получив что-то вроде PHP: if ($ldapdata['count'] == 0) { exit404('No results found!')} или если бесят простые условия: PHP: checkIfExit404($ldapdata['count'] == 0, 'No results found!') саму функцию определив как PHP: function checkIfExit404($check, $message) { if (!$check) return; header('HTTP/1.0 404 Not Found'); echo $message; exit;} И, кстати, если не обязательно показывать 404, можно было бы вообще PHP: $ldapdata['count'] == 0 || exit('No results found!') Работу с данными в цикле тоже хочется как-то переписать, как минимум - подготовив где-то снаружи объект со статическими данными и тем самым уменьшив количество кода в цикле.
А в for не нужно. И вообще, религиозная ненависть к for мне непонятна. Я тоже люблю и использую foreach там, где это уместно (мои говноскрипты на powershell состоят из foreach чуть менее, чем полностью). Если будет в дальнейшем необходимость — конечно, замечание разумное. Пока что её нет, с AD работает только этот модуль. А вот тут я против. Никак его не уменьшить, и так одна строка кода на один элемент данных (с заменой namespace). Только наплодить совершенно ненужных в данном случае объектов. И тоже принято. В теории — необязательно, достаточно не вернуть клиенту верный json (это не документировано). Но я не хочу лишний раз напрягать клиента парсингом. 404 и ойвсё. @E13, и ещё я избавился от лишней инициализации массива array_person. Теперь так: PHP: for ($i = 0; $i < $ldapdata['count']; $i++) { array_push($array_contacts, array( 'contactEntries' => array(array( 'entryId' => 'tel:0', 'label' => 'Внутренний', 'type' => 'tel', 'uri' => $ldapdata[$i]['ipphone'][0] )), 'contactId' => convertBinToMSSQLGuid($ldapdata[$i]['objectguid'][0]), 'countryCode' => 'ru', 'displayName' => $ldapdata[$i]['displayname'][0], 'fname' => $ldapdata[$i]['givenname'][0], 'lname' => $ldapdata[$i]['sn'][0] ));}
У меня есть ряд правил, которыми стараюсь руководствоваться. Например, более простой код лучше, чем более сложный. В этом смысле for проигрывает. В теории от него вообще можно избавиться, даже там, где нужна итерация по диапазону. Как минимум, в цикле на каждой итерации присваиваются одни и те же данные. Я про entryId, label, итп
Классы "плодят" не потому что "азаза классы лол", а чтобы качество кода улучшить. Зачем спрашивать вопросы, если все равно не собираешься улучшать код по советам?
Мне прежде всего бросился в глаза спагетти-стайл. Для одноразовых наколенных поделок годится, но если эта малая автоматизация имеет шансы прожить долго (и неизбежно переделываться) поддержка лапши превращается в аццкий адъ. Процедурный стиль вполне достойная вещь, но и в нем уместно разносить логику и вывод. Вовсе не обязательно тащить в каждый скриптик MVC, но хотя бы выделить представление в отдельную сущность — сам себе потом спасибо скажешь. Я, как и всякий непрограммист, которому довелось работать с пыхом, всё это проходил, радостно лепя echo прямо в функциях обработки данных и переключая контекст где попало. Много проклятий было к самому себе потом. И таки да, класс удобнейшая штука, когда задолбаешься выдумывать имена к расплодившимся, как тараканы, функциям и переменным.
Хех. Вот прямо недавно: набираем норот в команду. Оплата не то что бы большая, но для миддлов приемлемая по рынку. Жду от людей некоторой мотивированности и экспертизы: сам платил куда меньше, и примерно представляю, что должны уметь чуваки ценовой категории х2. Приходит чел. Начинаем работать - вроде норм, рекомендации с его стороны, по чуть рефакторинга. Но не сильно быстро всё пилит. Ок, может, в проекте разбирается пока. Даю задачку: сохранить некоторый сложный объект (сущность + пачка связанных с ней). Проходит день, второй. Пишу: чокагдила? Он: рефакторить надо, сейчас задачу решить не получится. Я: чо, рили, просто в базу сохранить не получится никак? (при том, что даже код уже есть, его по чуть адаптировать - и оп) Он: за говнокодом к индусам, тут уже проблемы, а дальше будет больше. Пришлось челу как раз примерно на картинке нарисовано пояснения давать. Что если сразу красиво не получается, надо сдать задачу, а красивостями заниматься уже потом. Хотя на деле скорее всего проблема была тупо в том, что чел параллельно чем-то занимался (не то ещё проект какой вёл, не то в носу ковырял, хз). В итоге разраб психанул, написал чота там негативное боссу, что в индусов играть без него. И проработав неделю был выдворен из проекта. Ну и особенный лулз в том, что из трёх людей, которых пытались нанять, ни один не оказался адекватным. Последний кто держится тоже работает со скоростью полчерепахи в час, но очень обстоятельно отчёты рисует. Так, что, не зная реальный объём кода и усилий на него, можно подумать, что реально работает, ахаха
Скорее не работал в крупных проектах и нет опыта \ знаний работы с чужим кодом. Или банально не нравиться этим заниматься.
Представляю его версию произошедшего: "Устроился вроде в нормальную команду, а спустя неделю понял, что они гонят лютый говнокод на скорость, решил не затягивать и попрощался с ними".
Никаких русских программистов не хватит переписывать говнокод за индусами. Иногда надо смириться и работать на том, что есть.
Я бы поставил на то, что не тем был занят человек, и использовал рефактор как отговорку. Потому что даже при плохом коде оно обычно работает иначе: в самом начале задачи чел пишет "ребят, тут что-то у вас не то, я предлагаю вот так разрулить, займёт столько-то". Собственно, этот товарищ так и делал поначалу. Потом пошёл негатив (босс запрашивал два мита в день, чел начал намекать, что это лишнее), потом я его пушнул по срокам, ну и стало ясно, что сейчас что-то неконструктивное начнётся. Возможно, он просто ждал большего от проекта и искал какую-то крутую команду, а тут мы с тусовкой в 2.5 юнита и проектом, который не то что бы большой и сложный. Менеджер - это априори виноватый человек Вписался раз в проект, который шёл под заголовком "три штуки за неделю". Чел предлагал допилить какой-то каталог. Каталог на вордпрессе, его мы знаем вдоль и поперёк, кеш хороший, чо б не взяться? Затем заглянул под капот, а там даже стандартные библиотеки неким старательным индусом подправлены так, что пришлось извиняться и отказываться.
Не могу, с*ка, молчать. Ненависть требует выхода. Ненависть к тем темно-радужным мультисексуальным тренсгендерам, что запихали жабаскрипт в каждый браузер, и никакой альтернативы этой мерзости не не оставили. Не, ну так-то язык и язык, и хрен бы с ним. Брейнфак ему в дышло. Кому и кобыла невеста. Если бы не вынужденные с ним объятия и сотни противоестественной любви с доками и гуглей. Следующий раз мена оооочень долго придется на это уговаривать! Это ж как надо умудриться такое уродить, что переменная может возвращаться из функции оператором return, а может не возвращаться! И никаких ворнингов в консоли. НЕНАВИСТЬ!!! Спросите, чего я так ругаюсь — это я запилил, наконец, анонимную голосовалку-лайкодром с отображением лайков онлайн. Глухой ночью перед самым дедлайном. Спасибо авторам Vue, сильно выручил.
Только не фронтенд (и уж тем паче бэк на js), меня от него подташнивает. Так то вопрос риторический, но лично я бы куда-то в системное программирование соскочил, возможно поближе к железу, но не микроконтроллеры. C\C++, но там много не заработаешь к сожалению
Я сейчас смотрю куда-то в сторону питона, мл и матмоделирования, Но пока не очень активно туда двигаюсь. И да, пых овладевает - на нем предлагают и больше, и дороже сейчас. Из перспективных тем которые стрельнут лет через пять - AR. Но пока хз как это будет. В текущем варианте жабоскрипт всё тот же, вроде бы. И всякие вуфории (там шарпы вроде) Java еще как вариант, но там хз чем люди живут Системное программирование было интересно лет десять назад, но надоело - ушёл кодить на пыхе в итоге, хех Сейчас ещё подумываю в железках поковыряться, но это не для коммерции на ближайшие лет 8-10
А зачем? Прекрасный язык. Не вижу причин соскакивать. Обычно в дополнение к PHP берут Go, эти два языка прекрасно дополняют друг друга. А доход слабо зависит от стека, он зависит от общего опыта. Из серии джун ~150, мидл ~250, сеньор ~350.
В целом с тех пор, как переполз с ВП на Ларавел, испытываю только положительные эмоции. Был удивлён деплоем джанги, который оказался куда менее заточен на гитфлоу и прочие радости. Единственное - хочется более лаконичных выражений. Пых сделал несколько робких шагов в этом направлении, но пока незачот
Через год после переползания на ларавел рекомендую попробовать поработать месяц-два на Симфони. Не раньше. Сам я к Laravel, как впрочем, и к Django отношусь негативно, если речь о серьезных проектах, однако для проектов "на коленке" они прекрасный выбор. Про гитфлоу: я не понял, каким боком к нему относится джанга.
Если "под рукой" нет более менее крупного проекта, то в полной мере проникнуться симфони не представляется возможным. Многие концепции, которые там есть, можно просто не понять, делая бложик на коленке.