drupflare/worker - v1.0.4
    Preparing search index...

    Variable XMLWRITER_FIXConst

    XMLWRITER_FIX: "\nuse Drupal\\drupflare\\Degradation;\n\nif (!class_exists('XMLWriter', false)) {\n\t/**\n\t * Enough of libxml's writer to generate a sitemap, and no more.\n\t *\n\t * Not final: it exists so a contrib class can extend it.\n\t */\n\tclass XMLWriter\n\t{\n\t\t/** @var string the document built so far */\n\t\tprivate $cfwBuf = '';\n\n\t\t/** @var array<int, array{name: string, children: bool, text: bool}> open elements, innermost last */\n\t\tprivate $cfwStack = [];\n\n\t\t/** @var bool whether the innermost start tag is still open and can still take attributes */\n\t\tprivate $cfwOpen = false;\n\n\t\t/** @var bool whether to pretty-print */\n\t\tprivate $cfwIndent = false;\n\n\t\t/** @var string what one indent level is */\n\t\tprivate $cfwIndentString = ' ';\n\n\t\t/** @var resource|null the stream openUri() opened, or null when this writer builds in memory */\n\t\tprivate $cfwHandle = null;\n\n\t\tpublic function openMemory(): bool\n\t\t{\n\t\t\t$this->cfwReset();\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic function openUri(string $uri): bool\n\t\t{\n\t\t\t$this->cfwReset();\n\t\t\t$handle = @fopen($uri, 'w');\n\t\t\tif ($handle === false) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t$this->cfwHandle = $handle;\n\t\t\treturn true;\n\t\t}\n\n\t\t/**\n\t\t * Content written through verbatim, which is what separates this from text().\n\t\t *\n\t\t * It still counts as content: the enclosing element has been given something, so its end tag\n\t\t * stays on the same line the way it does after text().\n\t\t */\n\t\tpublic function writeRaw(string $content): bool\n\t\t{\n\t\t\t$this->cfwCloseStart();\n\t\t\t$depth = count($this->cfwStack);\n\t\t\tif ($depth > 0) {\n\t\t\t\t$this->cfwStack[$depth - 1]['text'] = true;\n\t\t\t}\n\t\t\t$this->cfwBuf .= $content;\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic function setIndent(bool $enable): bool\n\t\t{\n\t\t\t$this->cfwIndent = $enable;\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic function setIndentString(string $indent): bool\n\t\t{\n\t\t\t$this->cfwIndentString = $indent;\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic function startDocument(\n\t\t\t?string $version = '1.0',\n\t\t\t?string $encoding = null,\n\t\t\t?string $standalone = null,\n\t\t): bool {\n\t\t\t$decl = '<?xml version=\"' . ($version ?? '1.0') . '\"';\n\t\t\tif ($encoding !== null && $encoding !== '') {\n\t\t\t\t$decl .= ' encoding=\"' . $encoding . '\"';\n\t\t\t}\n\t\t\tif ($standalone !== null && $standalone !== '') {\n\t\t\t\t$decl .= ' standalone=\"' . $standalone . '\"';\n\t\t\t}\n\t\t\t// the newline is UNCONDITIONAL, measured against libxml: it is part of the declaration\n\t\t\t// rather than part of indenting, and appears with setIndent(false) too\n\t\t\t$this->cfwBuf .= $decl . '?>' . \"\\n\";\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic function writePI(string $target, string $content): bool\n\t\t{\n\t\t\t$this->cfwCloseStart();\n\t\t\t$this->cfwNewline();\n\t\t\t$this->cfwBuf .= '<?' . $target . ' ' . $content . '?>';\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic function writeComment(string $content): bool\n\t\t{\n\t\t\t$this->cfwCloseStart();\n\t\t\t$this->cfwNewline();\n\t\t\t$this->cfwBuf .= '<!--' . $content . '-->';\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic function startElement(string $name): bool\n\t\t{\n\t\t\t$this->cfwCloseStart();\n\t\t\t// the PARENT now has an element child, which is what decides whether its own end tag\n\t\t\t// goes on a fresh line; libxml keeps a text-only element on one line\n\t\t\t$depth = count($this->cfwStack);\n\t\t\tif ($depth > 0) {\n\t\t\t\t$this->cfwStack[$depth - 1]['children'] = true;\n\t\t\t}\n\t\t\t$this->cfwNewline();\n\t\t\t$this->cfwBuf .= '<' . $name;\n\t\t\t$this->cfwStack[] = ['name' => $name, 'children' => false, 'text' => false];\n\t\t\t$this->cfwOpen = true;\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic function writeAttribute(string $name, string $value): bool\n\t\t{\n\t\t\t// silently dropping it would produce a sitemap missing its namespace, which validates\n\t\t\t// as XML and is rejected by every consumer\n\t\t\tif (!$this->cfwOpen) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t$this->cfwBuf .= ' ' . $name . '=\"' . $this->cfwEscape($value) . '\"';\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic function text(string $content): bool\n\t\t{\n\t\t\t$this->cfwCloseStart();\n\t\t\t$depth = count($this->cfwStack);\n\t\t\tif ($depth > 0) {\n\t\t\t\t$this->cfwStack[$depth - 1]['text'] = true;\n\t\t\t}\n\t\t\t$this->cfwBuf .= $this->cfwEscape($content);\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic function writeElement(string $name, ?string $content = null): bool\n\t\t{\n\t\t\t$this->startElement($name);\n\t\t\t// NULL and '' differ, and libxml distinguishes them: <x/> against <x></x>\n\t\t\tif ($content !== null) {\n\t\t\t\t$this->text($content);\n\t\t\t}\n\t\t\treturn $this->endElement();\n\t\t}\n\n\t\tpublic function endElement(): bool\n\t\t{\n\t\t\tif ($this->cfwStack === []) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t$frame = array_pop($this->cfwStack);\n\t\t\tif ($this->cfwOpen) {\n\t\t\t\t// nothing was ever written into it, so it collapses\n\t\t\t\t$this->cfwBuf .= '/>';\n\t\t\t\t$this->cfwOpen = false;\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif ($frame['children'] && !$frame['text']) {\n\t\t\t\t$this->cfwNewline();\n\t\t\t}\n\t\t\t$this->cfwBuf .= '</' . $frame['name'] . '>';\n\t\t\t// returning to the top level ends a line, measured: libxml emits it even with no\n\t\t\t// endDocument() at all, so it belongs to the element rather than to the document\n\t\t\tif ($this->cfwIndent && $this->cfwStack === []) {\n\t\t\t\t$this->cfwBuf .= \"\\n\";\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic function endDocument(): bool\n\t\t{\n\t\t\twhile ($this->cfwStack !== []) {\n\t\t\t\t$this->endElement();\n\t\t\t}\n\t\t\t$this->cfwCloseStart();\n\t\t\t// unconditional, but never doubled: with indent on, endElement() has already ended the\n\t\t\t// line and libxml does not add a second\n\t\t\tif ($this->cfwBuf !== '' && substr($this->cfwBuf, -1) !== \"\\n\") {\n\t\t\t\t$this->cfwBuf .= \"\\n\";\n\t\t\t}\n\t\t\t// A URI WRITER HAS TO REACH ITS FILE HERE. xmlsitemap calls endDocument() and then\n\t\t\t// file_get_contents() on the same uri to gzip it, so a buffer still held in memory\n\t\t\t// produces an empty .gz beside a sitemap that looks fine\n\t\t\tif ($this->cfwHandle !== null) {\n\t\t\t\t$this->flush(true);\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic function outputMemory(bool $flush = true): string\n\t\t{\n\t\t\t$out = $this->cfwBuf;\n\t\t\tif ($flush) {\n\t\t\t\t$this->cfwBuf = '';\n\t\t\t\t$this->cfwStack = [];\n\t\t\t\t$this->cfwOpen = false;\n\t\t\t}\n\t\t\treturn $out;\n\t\t}\n\n\t\t/**\n\t\t * BYTES for a uri writer and the DOCUMENT for a memory one, which is libxml own split.\n\t\t *\n\t\t * Returning the string in both cases would read as working: xmlsitemap ignores the return of\n\t\t * its periodic flushes, so the file would simply stay empty until something read it.\n\t\t */\n\t\tpublic function flush(bool $empty = true)\n\t\t{\n\t\t\tif ($this->cfwHandle === null) {\n\t\t\t\treturn $this->outputMemory($empty);\n\t\t\t}\n\t\t\t$written = fwrite($this->cfwHandle, $this->cfwBuf);\n\t\t\tif ($empty) {\n\t\t\t\t$this->cfwBuf = '';\n\t\t\t}\n\t\t\treturn $written === false ? 0 : $written;\n\t\t}\n\n\t\t/**\n\t\t * A method this writer does not implement degrades with a reason and answers false.\n\t\t *\n\t\t * @param array<int, mixed> $args\n\t\t * The arguments the caller passed.\n\t\t */\n\t\tpublic function __call(string $method, array $args): bool\n\t\t{\n\t\t\tif (class_exists(Degradation::class)) {\n\t\t\t\tDegradation::record(\n\t\t\t\t\t'xmlwriter.' . $method,\n\t\t\t\t\t'the XMLWriter stand-in does not implement ' . $method . '()',\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic function __destruct()\n\t\t{\n\t\t\tif ($this->cfwHandle === null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif ($this->cfwBuf !== '') {\n\t\t\t\t@fwrite($this->cfwHandle, $this->cfwBuf);\n\t\t\t\t$this->cfwBuf = '';\n\t\t\t}\n\t\t\t@fclose($this->cfwHandle);\n\t\t\t$this->cfwHandle = null;\n\t\t}\n\n\t\t/** shared by openMemory() and openUri(); a reopen abandons whatever was in flight */\n\t\tprivate function cfwReset(): void\n\t\t{\n\t\t\t$this->cfwBuf = '';\n\t\t\t$this->cfwStack = [];\n\t\t\t$this->cfwOpen = false;\n\t\t\tif ($this->cfwHandle !== null) {\n\t\t\t\t@fclose($this->cfwHandle);\n\t\t\t\t$this->cfwHandle = null;\n\t\t\t}\n\t\t}\n\n\t\t/** finishes an open start tag, which is what makes attributes order-sensitive */\n\t\tprivate function cfwCloseStart(): void\n\t\t{\n\t\t\tif ($this->cfwOpen) {\n\t\t\t\t$this->cfwBuf .= '>';\n\t\t\t\t$this->cfwOpen = false;\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * A newline plus one indent per open element, never before the very first node, and never\n\t\t * doubled after the declaration -- which already ends its own line.\n\t\t */\n\t\tprivate function cfwNewline(): void\n\t\t{\n\t\t\tif (!$this->cfwIndent || $this->cfwBuf === '') {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (substr($this->cfwBuf, -1) !== \"\\n\") {\n\t\t\t\t$this->cfwBuf .= \"\\n\";\n\t\t\t}\n\t\t\t$this->cfwBuf .= str_repeat($this->cfwIndentString, count($this->cfwStack));\n\t\t}\n\n\t\t/**\n\t\t * ONE escaper for both text and attributes, which is what libxml does.\n\t\t *\n\t\t * The obvious split -- ampersand and angle brackets in text, plus the double quote only in\n\t\t * attributes -- is wrong, measured: libxml escapes a double quote in TEXT content as well,\n\t\t * and leaves a single quote alone in both. Guessing produced exactly that split and the\n\t\t * oracle rejected it.\n\t\t */\n\t\tprivate function cfwEscape(string $s): string\n\t\t{\n\t\t\treturn str_replace(['&', '<', '>', '\"'], ['&amp;', '&lt;', '&gt;', '&quot;'], $s);\n\t\t}\n\t}\n}\n" = XMLWRITER_FIX_PHP

    A pure-PHP XMLWriter for a build without ext-xmlwriter.

    It is a class because simple_sitemap and xmlsitemap subclass \XMLWriter: the parent must exist when the subclass compiles, so it is declared as early as MB_FIX. The surface covers what both subclasses call (openUri, writeRaw included); writeCdata, startAttribute, writeDtd and the namespace variants have no caller and stay absent. openUri() makes it a streaming writer, so flush() returns bytes rather than the document.

    Guarded by if (!class_exists(...)) rather than eval(), so the body stays lintable.