Пните меня в правильном направлении, пожалуйста. Есть следующая задача: На фтп на протяжении дня падают зип архивы вида GUID.mbsu, GUID на данный момент две штуки (айдишники торговых). Нужно этот архив распаковать, достать оттуда xml - с этим я вроде разобрался. XML содержит информацию о заказах/оплатах в следующем виде Спойлер: Источник XML <T_ORDER_TITLE> <N_CARRY>true</N_CARRY> <N_CHECK_NUMBER></N_CHECK_NUMBER> <N_CLIENTID>198785</N_CLIENTID> <N_COMMENT></N_COMMENT> <N_CONTRACTID>81</N_CONTRACTID> <N_CREATE_DATE>1478604069724</N_CREATE_DATE> <N_DATE>1478604594096</N_DATE> <N_DELAY>true</N_DELAY> <N_FORMID>1</N_FORMID> <N_GEOADDRESS>проспект Михайла Грушевського, 82, Коломия, Івано-Франківська область, Украина</N_GEOADDRESS> <N_HAVE_DISCOUNT>false</N_HAVE_DISCOUNT> <N_ID>70ebca18-fa1c-4ab3-a93b-b762ad81138d</N_ID> <N_LAT>48.5259135</N_LAT> <N_LNG>25.0280832</N_LNG> <N_MESSAGE_NUMBER>0</N_MESSAGE_NUMBER> <N_PARENTID>198785</N_PARENTID> <N_PRICEID>22</N_PRICEID> <N_SHIPMENT_DATE>0</N_SHIPMENT_DATE> <N_SUM>358.0</N_SUM> <N_WAREHOUSE_ID>ALL</N_WAREHOUSE_ID> </T_ORDER_TITLE> <T_ORDER_TABLE> <N_DATE>1478604594096</N_DATE> <N_DISCOUNT_PERCENT>0.0</N_DISCOUNT_PERCENT> <N_FACTOR>1.0</N_FACTOR> <N_ID>70ebca18-fa1c-4ab3-a93b-b762ad81138d1000004215</N_ID> <N_LINE_NUMBER>1</N_LINE_NUMBER> <N_MANUAL_PRICE>false</N_MANUAL_PRICE> <N_NOMENID>1000004215</N_NOMENID> <N_NUMBER>1.0</N_NUMBER> <N_PRICE>37.0</N_PRICE> <N_SUM>37.0</N_SUM> <N_TITLEID>70ebca18-fa1c-4ab3-a93b-b762ad81138d</N_TITLEID> <N_UNIT_ID>ALL</N_UNIT_ID> </T_ORDER_TABLE> <T_CASH_ORDERS> <N_BASE_ID>51137cff-f8ca-4c08-88dd-062cf3602fc9</N_BASE_ID> <N_CARRY>true</N_CARRY> <N_CHECK_NUMBER></N_CHECK_NUMBER> <N_COMMENT></N_COMMENT> <N_CONTRACTID>162</N_CONTRACTID> <N_CREATE_DATE>1478764605513</N_CREATE_DATE> <N_DATE>1478764607794</N_DATE> <N_DEBT_NUMBER>Новый 433,80 $ 10.11.2016 07:56:19</N_DEBT_NUMBER> <N_DEBT_TYPE>Заказ</N_DEBT_TYPE> <N_FORMID>1</N_FORMID> <N_GEOADDRESS>М06, Закарпатська область, Украина</N_GEOADDRESS> <N_ID>f7670019-df2d-4d1a-b097-afe8502dbba1</N_ID> <N_LAT>48.4681651</N_LAT> <N_LNG>22.6181861</N_LNG> <N_MESSAGE_NUMBER>0</N_MESSAGE_NUMBER> <N_PARENTID>198594</N_PARENTID> <N_SUM>433.8</N_SUM> </T_CASH_ORDERS> T_ORDER_TITLE - общая информация о заказе T_ORDER_TABLE - информация по каждой позиции заказа T_CASH_ORDERS - оплата по заказу Этих элементов может быть много, типа несколько заказов сразу. Мне нужно для каждого заказа/оплаты получить xml вида: Спойлер: XML на выходе <DocID xmlns="Documents" CodeSpace="my" DocID="57614" VersionID="1" BranID="101" BranName="PCH"> <CreID xmlns="Subjects" SubjID="159"> <SubjName>Склад Машина</SubjName> </CreID> <DebID xmlns="Subjects" SubjID="1083"> <SubjName>Склад Хмельницький</SubjName> </DebID> <TemplID xmlns="Templates" TemplID="41" TemplName="Товар на склад"/> <PriceID xmlns="PriceHeads" PriceID="22" PriceName="Базова"/> <DocCode>43585518</DocCode> <ExtraDoc> </ExtraDoc> <Comments/> <GDS>-1</GDS> <DocDate>20161205</DocDate> <DocTax>0</DocTax> <DocSum>440</DocSum> <DocTaxSum>0</DocTaxSum> <AddrID/> <RateLimit>0</RateLimit> <Patterns xmlns="Patterns"> <Item GlobID="1000002707" ItemID="16149471" ItemName="Dekomarin 65cm A 20" ItemExt="" ItemShort="65cm A 20" ExtraCode="A 20" PerPack="1" PerCase="1" PerPall="1" Weight="8.7" Volume="0.063" SUF="" BaseTax="0" EAN="8690552310065" GDS="-1" AlcTax="" TAR="0" UnitFactor="1" UnitName="штука" UnitShort="шт." WGT="0" ProdID="1000000007" ProdName="On Grup" MarkID="1000000033" MarkName="D65m"> <BasePrice>38</BasePrice> <Price>38</Price> <Ordered>0</Ordered> <Quantity>2</Quantity> <Discount>0</Discount> </Item> </Patterns> </DocID> Пока получил общую информацию по заказам: Код (Text): <?php /** * @author new_bember * @copyright 2016 */ $dir = 'C:\in'; $files = scandir($dir); $filename = $files[2]; print_r($filename); $xml = simplexml_load_file("C:\\in\\".$filename) or die ("Error. Cannot create object"); foreach ($xml->T_ORDER_TITLE as $element) { echo "Order number: ".$element->N_ID . ", "; echo "SubjID: ".$element->N_PARENTID . ", "; echo "OrderSum: ".$element->N_SUM . "<br>"; } ?> А вот чего дальше делать, что-то не догоняю.. Я конечно курю все эти доки, но пинок в правильном направлении будет хорошим подспорьем. Заранее благодарен.
Ну таки сгенерировать. Сгенерировать вторую хмлку в посте, подставив туда данные из первой, айдишники товара/клиента. Я с этой хмл работаю как с массивом, это правильно вообще? Вот так вот я достал заказы и относящиеся к ним товары: Код (Text): <?php /** * @author new_bember * @copyright 2016 */ $dir = 'C:\in'; $files = scandir($dir); $filename = $files[2]; //print_r($filename); $xml = simplexml_load_file("C:\\in\\".$filename) or die ("Error. Cannot create object"); $order_count = $xml->T_ORDER_TITLE->count(); echo "Orders count: " . $order_count . "<br>"; $items_count = $xml->T_ORDER_TABLE->count(); echo "Items quantity: " . $items_count . "<br>"; $pko_count = $xml->T_CASH_ORDERS->count(); echo "Payments count: " . $pko_count . "<br>"; for ($i=0; $i<$order_count; $i++) { for ($j=0; $j<$items_count; $j++) { if ($xml->T_ORDER_TITLE[$i]->N_ID = $xml->T_ORDER_TABLE[$j]->N_TITLEID) echo "Ordered: " . $xml->T_ORDER_TITLE[$i]->N_ID . ", " . $xml->T_ORDER_TABLE[$j]->N_NOMENID . "<br>"; } } ?>
Ну если он массив да, как с массивом надо и работать)). создай ручками статический xml файл нужной тебе структуры, потом открывай его и добавляй нужные данные. Или же используя класс SimpleXMLElement генерируй его на лету.
Курю ман и готовлю болванку хмл, но пока спрошу, а реально ли сделать так: я в болванку сразу переменные в нужных местах забью, а потом в момент когда переменные инициализированы я файл открою и тут же сохраню уже с данными?
ага, делай через короткий синтаксис echo: <?=$foo?> и файл через include, но лучше через str_replace() и file_get_contents()
PHP: $order_number = $xml->T_ORDER_TITLE[0]->N_ID->__toString(); for ($i=0; $i<$items_count; $i++) { $item_order = $xml->T_ORDER_TABLE[$i]->N_TITLEID->__toString(); if ($item_order = $order_number) print_r ($xml->T_ORDER_TABLE[$i]->N_NOMENID); } Кто подскажет почему $item_order не меняется когда счётчик тикает? Чувствую, что мелочь какую-то упустил, а какую - не могу понять. --- Добавлено --- PHP: if (strcasecmp($item_order, $order_number) == 0) Вот оно чё не стреляло - незаряжено былО.
PHP: for ($i=0; $i<$order_count; $i++) { for ($j=0; $j<$items_count; $j++) { $order_number = $xml->T_ORDER_TITLE[$i]->N_ID->__toString(); $item_order = $xml->T_ORDER_TABLE[$j]->N_TITLEID->__toString(); if (strcasecmp($item_order, $order_number) == 0) echo "Ordered: " . $xml->T_ORDER_TITLE[$i]->N_ID . ", " . $xml->T_ORDER_TABLE[$j]->N_NOMENID . "<br>"; } } Ну вроде получаю я всё что нужно перебирая массив в этом цикле, а что у нас с видимостью переменных или как результат вернуть кроме как на экран? Мне в этом же цикле запускать str_replace() или функцию отдельно писать для заполнения файла и тут её вызывать?
документация по echo вместо echo собирать всё в переменную $buff .= 'тут текст'; точка означает такое примерно $buff = $buff.'тут текст'; можно в цикле
PHP: for ($i=0; $i<$order_count; $i++) { $ClientID = $xml->T_ORDER_TITLE[$i]->N_CLIENTID->__toString(); $neworder = str_replace("%ClientID%", $ClientID, $empty_order); $neworder->asXML($ClientID . ".xml"); Подскажите, пожалуйста, что не так с asXML? Тут у меня та самая ошибка про "call to a member function asxml() on a non-object".
По документации она возвращает строку или массив (если массив на входе был), у меня вроде строка получается, глянул var_dump и в отладчике. Мне кажется что проблема в отсутствии в заголовке строки <?xml version="1.0" encoding="UTF-8"?>, потому что вот это вот отрабатывает нормально: PHP: for ($i=0; $i<$order_count; $i++) { $ClientID = $xml->T_ORDER_TITLE[$i]->N_CLIENTID->__toString(); $neworder = str_replace("%ClientID%", $ClientID, $empty_order); var_dump($neworder); file_put_contents($ClientID.'.xml', $neworder); // $neworder->asXML($ClientID . ".xml"); // echo $neworder->asXML(); --- Добавлено --- HTML: <DocID xmlns="Documents" CodeSpace="SAV" DocID="" VersionID="1" BranID="101" BranName="PCH"> <CreID xmlns="Subjects" SubjID="%GUID%"> <SubjName></SubjName> </CreID> <DebID xmlns="Subjects" SubjID="%ClientID%"> <SubjName></SubjName> </DebID> <TemplID xmlns="Templates" TemplID="11"/> <PriceID xmlns="PriceHeads"/> <GDS>-1</GDS> <DocDate>%DocDate%</DocDate> <DocTax>0</DocTax> <DocSum>%OrderAmount%</DocSum> <DocTaxSum>0</DocTaxSum> <RateLimit>0</RateLimit> <Patterns xmlns="Patterns"> <Item GlobID="%ItemID%" GDS="-1"> <BasePrice></BasePrice> <Price>%Price%</Price> <Ordered>0</Ordered> <Quantity>%Qty%</Quantity> <Discount>0</Discount> </Item> </Patterns> </DocID> И ещё, верхнюю часть файла нужно заполнять за несколько проходов по очереди меняя переменные и давая на вход то что получилось в переменной $neworder? А каким макаром добавить несколько элементов <Item>?
а ты вызываешь метод у текста или массива, пытаешься с текстом или массивом работать как с объектом класса работает то что ты закомментировал? в цикле с помощью соединения строк если ты пошёл этим способом
А мне-то при наличии готовой болванки хмл, видимо правильнее работать с ней через file_put_contents(), я ведь только текст меняю, а __asXML() был бы смысл использовать если бы я генерировал хмл на лету, правильно?
Становится всё интереснее: Allowed memory size of 134217728 bytes exhausted (tried to allocate 79788736 bytes) Подскажите где накосячил? Чуствую, что нужно было где-то какие-то переменные обнулять или что-то типа того. Вот то что пытаюсь запустить: PHP: $dir = 'C:\in'; // папка входящих файлов $files = scandir($dir); $filename = $files[2]; // получаем имя файла через жопу, но это временно. //print_r($filename); // Переменные для замены $xGUID; $xClientID; $xDocDate; // check about unix date $xOrderAmount; $xItemID; $xPrice; $xQty; $pItems = '<Patterns xmlns="Patterns">'; $empty_order = file_get_contents('C:\in\order.xml'); $xml = simplexml_load_file("C:\\in\\".$filename) or die ("Error. Cannot create object"); $order_count = $xml->T_ORDER_TITLE->count(); echo "Orders count: " . $order_count . "<br>"; $items_count = $xml->T_ORDER_TABLE->count(); echo "Items quantity: " . $items_count . "<br>"; $pko_count = $xml->T_CASH_ORDERS->count(); echo "Payments count: " . $pko_count . "<br>"; for ($i=0; $i<$order_count; $i++) { $xClientID = $xml->T_ORDER_TITLE[$i]->N_CLIENTID->__toString(); $xOrderAmount = $xml->T_ORDER_TITLE[$i]->N_SUM->__toString(); $neworder = str_replace("%ClientID%", $xClientID, $empty_order); $neworder = str_replace('%OrderAmount%', $xOrderAmount, $neworder); // $neworder->asXML($ClientID . ".xml"); // echo $neworder->asXML(); for ($j=0; $j<$items_count; $j++) { $order_number = $xml->T_ORDER_TITLE[$i]->N_ID->__toString(); $item_order = $xml->T_ORDER_TABLE[$j]->N_TITLEID->__toString(); if (strcasecmp($item_order, $order_number) == 0) echo "Ordered: " . $xml->T_ORDER_TITLE[$i]->N_ID . ", " . "<br>"; $xItemID = $xml->T_ORDER_TABLE[$j]->N_NOMENID->__toString(); $xPrice = $xml->T_ORDER_TABLE[$j]->N_PRICE->__toString(); $xQty = $xml->T_ORDER_TABLE[$j]->N_NUMBER->__toString(); $pItems .= '<Patterns xmlns="Patterns"> <Item GlobID="'.$xItemID.'" GDS="-1"> <BasePrice></BasePrice> <Price>'.$xPrice.'</Price> <Ordered>0</Ordered> <Quantity>'.$xQty.'</Quantity> <Discount>0</Discount> </Item>'; $neworder = str_replace('<Patterns xmlns="Patterns">', $pItems, $neworder); file_put_contents($xClientID.'.xml', $neworder); } } var_dump($pItems);
А потому что в реальном мире с xml так не работают ) Они обычно большие и потому писать / читать их нужно потоком, иначе тебе никакой оперативки не хватит. XMLReader / XMLWriter тебе в помощь, чуть менее удобно конечно, но зато не упрешься в лимиты. Код (Text): // вот так уже давно быстрее, чем остальные варианты: echo "Orders count: $order_count <br>";
SimpleXML это не из той же оперы что и XMLReader / XMLWriter. В лимиты я упёрся потому, что скобки фигурные пропустил после IF. Всем спасибо за помощь, вроде готова основная часть: PHP: <?php /** * @author new_bember * @copyright 2016 */ $dir = 'C:\in'; // папка входящих файлов $files = scandir($dir); $filename = $files[2]; // получаем имя файла через жопу, но это временно. // Переменные для замены $xGUID = '159'; // Sales GUID 159/160 depends on filename $xClientID; // Выбрать другой из базы $xDocDate; // check about unix date. Done. $xOrderAmount; $xItemID; $xPrice; $xQty; $pItems = '<Patterns xmlns="Patterns">'; // --- $empty_order = file_get_contents('C:\in\order.xml'); $xml = simplexml_load_file("C:\\in\\".$filename) or die ("Error. Cannot create object"); $order_count = $xml->T_ORDER_TITLE->count(); //echo "Orders count: " . $order_count . "<br>"; $items_count = $xml->T_ORDER_TABLE->count(); //echo "Items quantity: " . $items_count . "<br>"; $pko_count = $xml->T_CASH_ORDERS->count(); //echo "Payments count: " . $pko_count . "<br>"; $baseMemory = memory_get_usage(); for ($i=0; $i<$order_count; $i++) { $xClientID = $xml->T_ORDER_TITLE[$i]->N_CLIENTID->__toString(); $xOrderAmount = $xml->T_ORDER_TITLE[$i]->N_SUM->__toString(); $ymd = gmdate("Ymd", substr($xml->T_ORDER_TITLE->N_CREATE_DATE->__toString(),0,10)); $neworder = str_replace('%ClientID%', $xClientID, $empty_order); $neworder = str_replace('%GUID%', $xGUID, $neworder); $neworder = str_replace('%OrderAmount%', $xOrderAmount, $neworder); $neworder = str_replace('%DocDate%', $ymd, $neworder); $pItems = '<Patterns xmlns="Patterns"> '; for ($j=0; $j<$items_count; $j++) { $order_number = $xml->T_ORDER_TITLE[$i]->N_ID->__toString(); $item_order = $xml->T_ORDER_TABLE[$j]->N_TITLEID->__toString(); if (strcasecmp($item_order, $order_number) == 0) { $xItemID = $xml->T_ORDER_TABLE[$j]->N_NOMENID->__toString(); $xPrice = $xml->T_ORDER_TABLE[$j]->N_PRICE->__toString(); $xQty = $xml->T_ORDER_TABLE[$j]->N_NUMBER->__toString(); $pItems .= '<Item GlobID="'.$xItemID.'" GDS="-1"> <BasePrice></BasePrice> <Price>'.$xPrice.'</Price> <Ordered>0</Ordered> <Quantity>'.$xQty.'</Quantity> <Discount>0</Discount> </Item> '; } } $neworder = str_replace('<Patterns xmlns="Patterns">', $pItems, $neworder); file_put_contents($xClientID.'.xml', $neworder); } Сейчас код обрабатывает нужный мне файл и формирует файлы хмл для последующего импорта в базу. Вопросы к специалистам: 1. Что в этом коде неправильно/некошерно/можно сделать лучше? 2. Сейчас скрипт ищет файл для обработки на фтп, но я заметил, что МТС (Украина) не даёт подключиться к фтп если у телефона соединение с интернетом EDGE (2G) (а телефоны не могут в 3ж, потому что они американцы), куда копать для того чтобы файлы для обработки получать из почты? 3. А ещё есть у меня MS SQL 2008r2 сервер с доступом по впн - есть идеи как к нему запрос можно сделать из этого же скрипта?
тебе с этого надо было начинать https://php.ru/forum/threads/php-to-ms-sql-server-2016.61353/#post-495543 там эта тема и обсуждается
Пока остаётся один вопрос, подскажите оптимально где почитать про получение файла из аттача почты. Скрипт на сайте, почта там же.