403Webshell
Server IP : 188.114.96.3  /  Your IP : 216.73.216.143
Web Server : Apache
System : Linux sv058.home.net.pl 6.8.2 husak_dirty_pages_fix #1 SMP PREEMPT_DYNAMIC Tue Apr 2 22:06:51 CEST 2024 x86_64
User :  ( 3194769)
PHP Version : 8.5.12
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : ON  |  Sudo : ON  |  Pkexec : OFF
Directory :  /polana/includes/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /polana/includes/tklm_word_v5.php
<?php
declare(strict_types=1);
/** TKLM Polana 2026 — Odczyt wersji językowych i eksport Word PL/EN/DE/ES.
 * Brak zmian w bazie, brak sieci, brak kluczy API, brak ZipArchive/tempnam.
 */
require_once __DIR__ . '/functions.php';

function tklm_v5_rows(int $menuId): array {
    if ($menuId < 1) throw new RuntimeException('Nieprawidłowe ID menu.');
    $q=db()->prepare('SELECT * FROM menus WHERE id=? LIMIT 1'); $q->execute([$menuId]);
    $menu=$q->fetch(PDO::FETCH_ASSOC);
    if (!$menu) throw new RuntimeException('Karta menu nie istnieje.');
    $q=db()->prepare('SELECT * FROM menu_categories WHERE menu_id=? ORDER BY sort_order,id');
    $q->execute([$menuId]); $cats=$q->fetchAll(PDO::FETCH_ASSOC);
    $q=db()->prepare('SELECT i.* FROM menu_items i INNER JOIN menu_categories c ON c.id=i.category_id WHERE c.menu_id=? ORDER BY c.sort_order,c.id,i.sort_order,i.id');
    $q->execute([$menuId]); $by=[];
    foreach ($q->fetchAll(PDO::FETCH_ASSOC) as $it) $by[(int)$it['category_id']][]=$it;
    foreach ($cats as &$cat) $cat['items']=$by[(int)$cat['id']]??[];
    unset($cat);
    return [$menu,$cats];
}
function tklm_v7_type_rank(string $type): int {
    return match($type) {
        'food' => 1,
        'soft' => 2,
        'wine' => 3,
        default => 99,
    };
}
function tklm_v7_type_label(string $type, string $lang): string {
    $map=[
        'pl'=>['food'=>'Dania','soft'=>'Napoje bezalkoholowe','wine'=>'Wina'],
        'en'=>['food'=>'Food','soft'=>'Soft drinks','wine'=>'Wines'],
        'de'=>['food'=>'Speisen','soft'=>'Alkoholfreie Getränke','wine'=>'Weine'],
        'es'=>['food'=>'Platos','soft'=>'Bebidas sin alcohol','wine'=>'Vinos'],
    ];
    return $map[$lang][$type] ?? ($map['pl'][$type] ?? ucfirst($type));
}
/**
 * Pobiera komplet powiazanych kart (np. Dania + Napoje bezalkoholowe + Wina)
 * o tej samej nazwie i tym samym okresie obowiazywania. Kazda karta stanie sie
 * osobna strona w Word/PDF.
 * @return array<int,array{menu:array,categories:array}>
 */
function tklm_v7_bundle_rows(int $menuId): array {
    if ($menuId < 1) throw new RuntimeException('Nieprawidłowe ID menu.');
    [$sourceMenu,] = tklm_v5_rows($menuId);
    $q = db()->prepare(
        'SELECT * FROM menus
         WHERE name = ?
           AND ((valid_from IS NULL AND ? IS NULL) OR valid_from = ?)
           AND ((valid_to IS NULL AND ? IS NULL) OR valid_to = ?)
         ORDER BY id'
    );
    $q->execute([
        (string)$sourceMenu['name'],
        $sourceMenu['valid_from'] ?? null, $sourceMenu['valid_from'] ?? null,
        $sourceMenu['valid_to'] ?? null, $sourceMenu['valid_to'] ?? null,
    ]);
    $menus = $q->fetchAll(PDO::FETCH_ASSOC);
    if (!$menus) $menus = [$sourceMenu];
    usort($menus, static function(array $a, array $b): int {
        $ra = tklm_v7_type_rank((string)($a['menu_type'] ?? ''));
        $rb = tklm_v7_type_rank((string)($b['menu_type'] ?? ''));
        return $ra <=> $rb ?: ((int)$a['id'] <=> (int)$b['id']);
    });
    // Jedna aktualna karta na rodzaj: bez powielania poprzednich wersji.
    // Wybieramy jawnie wskazana karte dla jej typu, a najnowsza opublikowana
    // karte dla pozostalych rodzajow w tym samym zestawie nazwa/data.
    $selected=[];
    foreach ($menus as $candidate) {
        $type=(string)($candidate['menu_type']??'food');
        if (!in_array($type,['food','soft','wine'],true)) continue;
        if ((string)($candidate['status']??'') !== 'published' && (int)$candidate['id'] !== $menuId) continue;
        if (!isset($selected[$type]) || (int)$candidate['id'] > (int)$selected[$type]['id']) $selected[$type]=$candidate;
    }
    $sourceType=(string)($sourceMenu['menu_type']??'food');
    $selected[$sourceType]=$sourceMenu;
    uksort($selected,static fn(string $a,string $b):int=>tklm_v7_type_rank($a)<=>tklm_v7_type_rank($b));
    $out=[];
    foreach ($selected as $menu) {
        [$fullMenu,$cats]=tklm_v5_rows((int)$menu['id']);
        $visible=false;
        foreach ($cats as $cat) {
            if (empty($cat['active'])) continue;
            foreach ($cat['items'] ?? [] as $it) {
                if (!empty($it['active']) && !empty($it['available'])) { $visible=true; break 2; }
            }
        }
        if (!$visible) continue;
        $out[]=['menu'=>$fullMenu,'categories'=>$cats];
    }
    if (!$out) throw new RuntimeException('Brak aktywnych pozycji w powiązanych kartach.');
    return $out;
}
function tklm_v5_status(int $menuId, string $lang): array {
    if (!in_array($lang,['pl','en','de','es'],true)) throw new RuntimeException('Nieznany język.');
    $bundle=tklm_v7_bundle_rows($menuId);
    $present=0; $required=0; $visible=0; $missing=[];
    foreach($bundle as $pack) {
        $menu=$pack['menu'];
        $cats=$pack['categories'];
        foreach($cats as $cat) {
            if (!(int)$cat['active']) continue;
            $items=array_values(array_filter($cat['items'],static fn(array $it):bool=>(int)$it['active']===1 && (int)$it['available']===1));
            if (!$items) continue;
            if ($lang !== 'pl' && trim((string)$cat['name'])!=='') {
                $required++;
                if (trim((string)($cat['name_'.$lang]??''))!=='') $present++;
                else $missing[]='Karta #'.(int)$menu['id'].' / kategoria #'.(int)$cat['id'];
            }
            foreach($items as $it) {
                $visible++;
                if ($lang==='pl') continue;
                foreach(['name','description','allergens'] as $field) {
                    if (trim((string)($it[$field]??''))==='') continue;
                    $required++;
                    if (trim((string)($it[$field.'_'.$lang]??''))!=='') $present++;
                    else $missing[]='Karta #'.(int)$menu['id'].' / pozycja #'.(int)$it['id'].': '.$field;
                }
            }
        }
    }
    return ['visible'=>$visible,'required'=>$required,'present'=>$present,'missing'=>$missing,
       'available'=>$visible>0 && ($lang==='pl'||$present>0),
       'ready'=>$visible>0 && ($lang==='pl'||($required>0&&$present===$required))];
}
function tklm_v5_word_buttons(int $menuId): string {
    if ($menuId < 1) return '';
    static $cache=[];
    if(isset($cache[$menuId])) return $cache[$menuId];
    $buttons='';
    try {
        foreach(['en','de','es'] as $lang) {
            $s=tklm_v5_status($menuId,$lang);
            if (!$s['available']) continue;
            $draft=!$s['ready'];
            $href='/admin/tklm-word-export-v5.php?menu_id='.$menuId.'&amp;lang='.$lang.($draft?'&amp;draft=1':'');
            $label='Word '.strtoupper($lang).($draft?' (roboczy)':'').' ↓';
            $title=$draft ? 'Brakujących pól: '.count($s['missing']).'. Sprawdź przed drukiem.' : 'Gotowa karta '.strtoupper($lang).' do druku';
            $buttons.=' <a class="btn btn-small btn-light" style="display:inline-block;white-space:nowrap;margin:2px" href="'.$href.'" title="'.htmlspecialchars($title,ENT_QUOTES,'UTF-8').'">'.htmlspecialchars($label,ENT_QUOTES,'UTF-8').'</a>';
            $pdf='/admin/tklm-pdf-export-v6.php?menu_id='.$menuId.'&amp;lang='.$lang.($draft?'&amp;draft=1':'').'&amp;download=1';
            $pdfLabel='PDF '.strtoupper($lang).($draft?' (roboczy)':'').' ↓';
            $buttons.=' <a class="btn btn-small btn-light" style="display:inline-block;white-space:nowrap;margin:2px" target="_blank" rel="noopener" href="'.$pdf.'" title="Zapisz PDF A4 dla '.strtoupper($lang).'">'.htmlspecialchars($pdfLabel,ENT_QUOTES,'UTF-8').'</a>';
        }
    } catch(Throwable $e) { error_log('[TKLM Word V5] '.$e->getMessage()); }
    return $cache[$menuId]=$buttons;
}

function tklm_v5_word_xml(string $s): string {
    $s = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F]/', '', $s) ?? '';
    return htmlspecialchars($s, ENT_QUOTES | ENT_XML1 | ENT_SUBSTITUTE, 'UTF-8');
}
function tklm_v5_word_para(string $text, string $style = 'Normal', string $align = ''): string {
    $p = '<w:pPr><w:pStyle w:val="' . tklm_v5_word_xml($style) . '"/>';
    if ($align !== '') $p .= '<w:jc w:val="' . tklm_v5_word_xml($align) . '"/>';
    $p .= '</w:pPr>';
    $lines = explode("\n", str_replace(["\r\n", "\r"], "\n", $text));
    $t = '';
    foreach ($lines as $index => $line) {
        if ($index) $t .= '<w:br/>';
        $t .= '<w:t xml:space="preserve">' . tklm_v5_word_xml($line) . '</w:t>';
    }
    return '<w:p>' . $p . '<w:r>' . $t . '</w:r></w:p>';
}
function tklm_v5_word_cell(string $content, int $width): string {
    return '<w:tc><w:tcPr><w:tcW w:w="' . $width . '" w:type="dxa"/><w:vAlign w:val="top"/></w:tcPr>' . $content . '</w:tc>';
}
function tklm_v5_word_price(array $item): string {
    $p = trim((string)($item['price_text'] ?? ''));
    if ($p !== '') return $p;
    if (isset($item['price']) && $item['price'] !== '' && $item['price'] !== null) {
        return number_format((float)$item['price'], 0, ',', ' ') . ' zł';
    }
    return '';
}
/**
 * Jedno logo dla PL/EN/DE/ES. Ten sam plik jest wyswietlany w publicznym menu.
 * Brak zasobu to blad eksportu - nie wysylamy Worda bez logo.
 */
function tklm_v6_word_logo_bytes(): string {
    $path = dirname(__DIR__).'/assets/img/logo.png';
    if (!is_file($path) || !is_readable($path)) throw new RuntimeException('Brak logo: /assets/img/logo.png.');
    $bytes = file_get_contents($path);
    if ($bytes === false || strlen($bytes) < 100 || substr($bytes,0,8) !== "\x89PNG\r\n\x1a\n") {
        throw new RuntimeException('Logo PNG jest uszkodzone lub niedostepne.');
    }
    return $bytes;
}
function tklm_v6_word_logo_paragraph(): string {
    // Wymiary grafiki zachowuja proporcje oryginalnego PNG (1200x1105).
    $meta=getimagesizefromstring(tklm_v6_word_logo_bytes());
    if (!is_array($meta) || (int)$meta[0]<1 || (int)$meta[1]<1) throw new RuntimeException('Nie mozna odczytac wymiarow logo.');
    $cx=1480000;
    $cy=(int)round($cx * (int)$meta[1]/(int)$meta[0]);
    return '<w:p><w:pPr><w:jc w:val="center"/><w:spacing w:after="100"/></w:pPr><w:r><w:drawing>'
      .'<wp:inline distT="0" distB="0" distL="0" distR="0"><wp:extent cx="'.$cx.'" cy="'.$cy.'"/>'
      .'<wp:docPr id="1" name="Logo Polana" descr="Logo Moja Polana Smakow"/>'
      .'<a:graphic><a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture">'
      .'<pic:pic><pic:nvPicPr><pic:cNvPr id="0" name="logo.png"/><pic:cNvPicPr/></pic:nvPicPr>'
      .'<pic:blipFill><a:blip r:embed="rIdLogo"/><a:stretch><a:fillRect/></a:stretch></pic:blipFill>'
      .'<pic:spPr><a:xfrm><a:off x="0" y="0"/><a:ext cx="'.$cx.'" cy="'.$cy.'"/></a:xfrm>'
      .'<a:prstGeom prst="rect"><a:avLst/></a:prstGeom></pic:spPr></pic:pic>'
      .'</a:graphicData></a:graphic></wp:inline></w:drawing></w:r></w:p>';
}
/** @return array{missing:array<string>, xml:string, count:int} */
function tklm_v5_word_document_parts(array $menu, array $cats, string $lang, bool $draft, ?array $bundleOverride=null): array {
    if (!in_array($lang,['pl','en','de','es'],true)) throw new RuntimeException('Język musi być PL, EN, DE albo ES.');
    $allerg=['pl'=>'Alergeny: ','en'=>'Allergens: ','de'=>'Allergene: ','es'=>'Alérgenos: '];
    $missing=[]; $count=0;
    $bundle=$bundleOverride ?? tklm_v7_bundle_rows((int)$menu['id']);
    $body='';
    $pageNo=0;
    foreach ($bundle as $pack) {
        $pageNo++;
        $curMenu=$pack['menu'];
        $curCats=$pack['categories'];
        if ($pageNo > 1) {
            $body .= '<w:p><w:r><w:br w:type="page"/></w:r></w:p>';
        }
        $body.=tklm_v6_word_logo_paragraph();
        // Wersja 12.2: po logo od razu wlasciwe kategorie i pozycje menu.
        // Nie drukujemy ozdobnych naglowkow KARTA RESTAURACJI / RESTAURANT MENU,
        // rodzaju karty (Food / Soft drinks / Wines) ani miasta i daty.
        // Podzial na osobne strony i graficzny podpis w stopce pozostaja bez zmian.
        foreach($curCats as $cat) {
            if (empty($cat['active'])) continue;
            $items=array_values(array_filter($cat['items']??[],static fn(array $it):bool=>!empty($it['active'])&&!empty($it['available'])));
            if (!$items) continue;
            $sourceCat=trim((string)($cat['name']??''));
            $catName=trim((string)($cat[$lang==='pl'?'name':'name_'.$lang]??''));
            if ($lang!=='pl' && $sourceCat!=='' && $catName==='') {
                $missing[]='Karta #'.(int)$curMenu['id'].' / kategoria #'.(int)$cat['id'];
                $catName='['.strtoupper($lang).' MISSING] '.$sourceCat;
            }
            $body.=tklm_v5_word_para($catName,'Category','center');
            foreach($items as $it) {
                $count++;
                $content=[];
                foreach(['name','description','allergens'] as $field) {
                    $source=trim((string)($it[$field]??''));
                    $key=$lang==='pl'?$field:$field.'_'.$lang;
                    $out=trim((string)($it[$key]??''));
                    if ($lang!=='pl' && $source!=='' && $out==='') {
                        $missing[]='Karta #'.(int)$curMenu['id'].' / pozycja #'.(int)$it['id'].': '.$field;
                        $out='['.strtoupper($lang).' MISSING] '.$source;
                    }
                    $content[$field]=$out;
                }
                $left=tklm_v5_word_para($content['name'],'Dish');
                if ($content['description']!=='') $left.=tklm_v5_word_para($content['description'],'Description');
                if ($content['allergens']!=='') $left.=tklm_v5_word_para($allerg[$lang].$content['allergens'],'Small');
                $right=tklm_v5_word_para(tklm_v5_word_price($it),'Price','right');
                $body.='<w:tbl><w:tblPr><w:tblW w:w="9300" w:type="dxa"/><w:tblInd w:w="0" w:type="dxa"/><w:tblCellMar><w:bottom w:w="125" w:type="dxa"/></w:tblCellMar></w:tblPr>';
                $body.='<w:tblGrid><w:gridCol w:w="7700"/><w:gridCol w:w="1600"/></w:tblGrid>';
                $body.='<w:tr><w:trPr><w:cantSplit/></w:trPr>'.tklm_v5_word_cell($left,7700).tklm_v5_word_cell($right,1600).'</w:tr></w:tbl>';
            }
        }
        // Oryginalny podpis graficzny jest w stopce dokumentu, na kazdej stronie.
    }
    if (!$count) throw new RuntimeException('Karta nie zawiera aktywnych i dostępnych pozycji.');
    if ($lang!=='pl' && $missing && !$draft) throw new RuntimeException('Brak '.count($missing).' pól '.strtoupper($lang).'. Uzupełnij tłumaczenia lub wybierz wersję roboczą.');
    $body.='<w:sectPr><w:footerReference w:type="default" r:id="rIdFooter"/><w:pgSz w:w="11906" w:h="16838"/><w:pgMar w:top="1080" w:right="1250" w:bottom="1320" w:left="1250" w:header="600" w:footer="480"/><w:cols w:space="720"/></w:sectPr>';
    return ['missing'=>$missing,'count'=>$count,'xml'=>'<?xml version="1.0" encoding="UTF-8" standalone="yes"?><w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture"><w:body>'.$body.'</w:body></w:document>'];
}

function tklm_v8_signature_bytes(): string {
    $p=dirname(__DIR__).'/assets/img/tklm_andrzej_polan_signature.png';
    if(!is_file($p) || !is_readable($p)) throw new RuntimeException('Brak podpisu w assets/img/tklm_andrzej_polan_signature.png.');
    $raw=file_get_contents($p);
    if($raw===false || substr($raw,0,8)!=="\x89PNG\r\n\x1a\n") throw new RuntimeException('Nieprawidłowa grafika podpisu.');
    return $raw;
}
function tklm_v8_footer_xml(): string {
    // Oryginalny podpis graficzny z polskiej karty, proporcje ok. 2.3:1.
    $cx=1750000; $cy=1002000;
    return '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
    .'<w:ftr xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"'
    .' xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"'
    .' xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"'
    .' xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"'
    .' xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture">'
    .'<w:p><w:pPr><w:jc w:val="center"/></w:pPr><w:r><w:drawing>'
    .'<wp:inline distT="0" distB="0" distL="0" distR="0"><wp:extent cx="'.$cx.'" cy="'.$cy.'"/>'
    .'<wp:docPr id="7" name="Podpis Andrzej Polan"/>'
    .'<a:graphic><a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture">'
    .'<pic:pic><pic:nvPicPr><pic:cNvPr id="8" name="podpis.png"/><pic:cNvPicPr/></pic:nvPicPr>'
    .'<pic:blipFill><a:blip r:embed="rIdSignature"/><a:stretch><a:fillRect/></a:stretch></pic:blipFill>'
    .'<pic:spPr><a:xfrm><a:off x="0" y="0"/><a:ext cx="'.$cx.'" cy="'.$cy.'"/></a:xfrm>'
    .'<a:prstGeom prst="rect"><a:avLst/></a:prstGeom></pic:spPr></pic:pic>'
    .'</a:graphicData></a:graphic></wp:inline></w:drawing></w:r></w:p></w:ftr>';
}
function tklm_v5_word_zip(array $parts): string {
    $style = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><w:styles xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">';
    $defs = [
        ['Normal',20,'242424',false,100,0],
        ['Brand',33,'292d23',true,160,100],
        ['Subtitle',20,'6d715d',false,140,160],
        ['Category',26,'2a4228',true,360,180],
        ['Dish',21,'151515',true,25,25],
        ['Description',18,'666666',false,35,55],
        ['Price',21,'151515',true,25,20],
        ['Small',16,'6a6a6a',false,150,70],
        ['Warning',19,'b42318',true,210,110],
    ];
    foreach ($defs as [$id,$size,$color,$bold,$before,$after]) {
        $style .= '<w:style w:type="paragraph" w:styleId="'.$id.'"><w:name w:val="'.$id.'"/><w:pPr><w:spacing w:before="'.$before.'" w:after="'.$after.'"/></w:pPr><w:rPr><w:rFonts w:ascii="Calibri" w:hAnsi="Calibri"/><w:color w:val="'.$color.'"/><w:sz w:val="'.$size.'"/>'.($bold?'<w:b/>':'').'</w:rPr></w:style>';
    }
    $style .= '</w:styles>';
    $types = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types"><Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/><Default Extension="xml" ContentType="application/xml"/><Default Extension="png" ContentType="image/png"/><Override PartName="/word/document.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"/><Override PartName="/word/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml"/><Override PartName="/word/footer1.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml"/></Types>';
    $rels = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="word/document.xml"/></Relationships>';
    $wordrels = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/><Relationship Id="rIdLogo" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" Target="media/logo.png"/><Relationship Id="rIdFooter" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer" Target="footer1.xml"/></Relationships>';
    $files = [
        '[Content_Types].xml' => $types,
        '_rels/.rels' => $rels,
        'word/document.xml' => $parts['xml'],
        'word/styles.xml' => $style,
        'word/_rels/document.xml.rels' => $wordrels,
        'word/media/logo.png' => tklm_v6_word_logo_bytes(),
        'word/footer1.xml' => tklm_v8_footer_xml(),
        'word/_rels/footer1.xml.rels' => '<?xml version="1.0" encoding="UTF-8"?><Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rIdSignature" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" Target="media/signature.png"/></Relationships>',
        'word/media/signature.png' => tklm_v8_signature_bytes(),
    ];
    $zip=''; $directory=''; $entries=0;
    $t=getdate();
    $dosDate=((max(1980,(int)$t['year'])-1980)<<9)|((int)$t['mon']<<5)|(int)$t['mday'];
    $dosTime=((int)$t['hours']<<11)|((int)$t['minutes']<<5)|((int)$t['seconds']>>1);
    foreach ($files as $name => $content) {
        $name=(string)$name;
        $content=(string)$content;
        $size=strlen($content); $nlen=strlen($name);
        $crc=crc32($content);
        $offset=strlen($zip);
        // Lokalny naglowek ZIP (PK 03 04): store, bez descriptorow.
        $zip .= pack('VvvvvvVVVvv',0x04034b50,20,0,0,$dosTime,$dosDate,$crc,$size,$size,$nlen,0).$name.$content;
        // Central directory (PK 01 02).
        $directory .= pack('VvvvvvvVVVvvvvvVV',0x02014b50,20,20,0,0,$dosTime,$dosDate,$crc,$size,$size,$nlen,0,0,0,0,0,$offset).$name;
        $entries++;
    }
    $dirOffset=strlen($zip);
    $zip.=$directory;
    $zip.=pack('VvvvvVVv',0x06054b50,0,0,$entries,$entries,strlen($directory),$dirOffset,0);
    if(strlen($zip)<250) throw new RuntimeException('Blad generowania DOCX.');
    return $zip;
}

Youez - 2016 - github.com/yon3zu
LinuXploit