예제 #1
0
 /**
  * Hook function which
  * - Sets the version correctly when editing a topic
  * - Redirects to the first topic in a manual if the user requested a bare manual URL
  * - Redirect to the landing page when there are no available versions
  */
 public function onArticleFromTitleQuickLookup(&$title, &$article)
 {
     global $wgScriptPath;
     if (preg_match('/&action=edit/', $_SERVER['PATH_INFO'])) {
         // Check referrer and see if we're coming from a doc page.
         // If so, we're editing it, so we should force the version
         // to be from the referrer.
         if (preg_match('/^' . str_replace("/", "\\/", $wgScriptPath) . '\\/' . PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . '\\/(\\w+)\\/((latest|[\\w\\.]*)\\/)?(\\w+)\\/?/i', $_SERVER['HTTP_REFERER'], $match)) {
             $targetProduct = $match[1];
             $targetVersion = $match[3];
             if ($targetVersion == "latest") {
                 PonyDocsProductVersion::SetSelectedVersion($targetProduct, PonyDocsProductVersion::GetLatestReleasedVersion($targetProduct)->getVersionName());
             } else {
                 PonyDocsProductVersion::SetSelectedVersion($targetProduct, $targetVersion);
             }
         }
     }
     // Match a URL like /Documentation/PRODUCT
     if (preg_match('/^' . str_replace("/", "\\/", $wgScriptPath) . '\\/' . PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . '\\/([' . PONYDOCS_PRODUCT_LEGALCHARS . ']+)$/i', $_SERVER['PATH_INFO'], $match)) {
         $targetProduct = $match[1];
         $version = PonyDocsProductVersion::GetVersions($targetProduct, TRUE);
         //check for product not found
         if (empty($version)) {
             PonyDocsExtension::redirectToLandingPage();
             return true;
         }
     }
     // Matches a URL like /Documentation/PRODUCT/VERSION/MANUAL
     // TODO: Should match PONYDOCS_PRODUCTMANUAL_LEGALCHARS instead of \w at the end
     if (preg_match('/^' . str_replace("/", "\\/", $wgScriptPath) . '\\/' . PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . '\\/([' . PONYDOCS_PRODUCT_LEGALCHARS . ']+)\\/([' . PONYDOCS_PRODUCTVERSION_LEGALCHARS . ']+)\\/(\\w+)\\/?$/i', $_SERVER['PATH_INFO'], $match)) {
         $targetProduct = $match[1];
         $targetVersion = $match[2];
         $targetManual = $match[3];
         $p = PonyDocsProduct::GetProductByShortName($targetProduct);
         if (!$p instanceof PonyDocsProduct) {
             $wgHooks['BeforePageDisplay'][] = "PonyDocsExtension::handle404";
             return false;
         }
         // User wants to find first topic in a requested manual.
         // Load up versions
         PonyDocsProductVersion::LoadVersionsForProduct($targetProduct);
         // Determine version
         if ($targetVersion == '') {
             // No version specified, use the user's selected version
             $ver = PonyDocsProductVersion::GetVersionByName($targetProduct, PonyDocsProductVersion::GetSelectedVersion($targetProduct));
         } else {
             if (strtolower($targetVersion) == "latest") {
                 // User wants the latest version.
                 $ver = PonyDocsProductVersion::GetLatestReleasedVersion($targetProduct);
             } else {
                 // Okay, they want to get a version by a specific name
                 $ver = PonyDocsProductVersion::GetVersionByName($targetProduct, $targetVersion);
             }
         }
         if (!$ver) {
             if (PONYDOCS_DEBUG) {
                 error_log("DEBUG [" . __METHOD__ . ":" . __LINE__ . "] redirecting to {$wgScriptPath}/" . PONYDOCS_DOCUMENTATION_NAMESPACE_NAME);
             }
             header('Location: ' . $wgScriptPath . '/' . PONYDOCS_DOCUMENTATION_NAMESPACE_NAME);
             die;
         }
         // Okay, the version is valid, let's set the user's version.
         PonyDocsProductVersion::SetSelectedVersion($targetProduct, $ver->getVersionName());
         PonyDocsProductManual::LoadManualsForProduct($targetProduct);
         $manual = PonyDocsProductManual::GetManualByShortName($targetProduct, $targetManual);
         if (!$manual) {
             // Rewrite to Main documentation
             if (PONYDOCS_DEBUG) {
                 error_log("DEBUG [" . __METHOD__ . ":" . __LINE__ . "] redirecting to {$wgScriptPath}/" . PONYDOCS_DOCUMENTATION_NAMESPACE_NAME);
             }
             header('Location: ' . $wgScriptPath . '/' . PONYDOCS_DOCUMENTATION_NAMESPACE_NAME);
             die;
         } elseif (!$manual->isStatic()) {
             // Get the TOC out of here! heehee
             $toc = new PonyDocsTOC($manual, $ver, $p);
             list($toc, $prev, $next, $start) = $toc->loadContent();
             //Added empty check for WEB-10038
             if (empty($toc)) {
                 PonyDocsExtension::redirectToLandingPage();
                 return FALSE;
             }
             foreach ($toc as $entry) {
                 if (isset($entry['link']) && $entry['link'] != "") {
                     // We found the first article in the manual with a link.
                     // Redirect to it.
                     if (PONYDOCS_DEBUG) {
                         error_log("DEBUG [" . __METHOD__ . ":" . __LINE__ . "] redirecting to " . $entry['link']);
                     }
                     header("Location: " . $entry['link']);
                     die;
                 }
             }
             //Replace die with a warning log and redirect
             error_log("WARNING [" . __METHOD__ . ":" . __LINE__ . "] redirecting to " . PonyDocsExtension::getDefaultUrl());
             PonyDocsExtension::redirectToLandingPage();
             return FALSE;
         }
     }
     return TRUE;
 }
예제 #2
0
/**
 * Our primary setup function simply handles URL rewrites for aliasing (per spec) and calls our PonyDocsWiki singleton instance
 * to ensure it runs the data retrieval functions for versions and manuals and the like. 
 */
function efPonyDocsSetup()
{
    global $wgPonyDocs, $wgScriptPath, $wgArticlePath;
    // force mediawiki to start session for anonymous traffic
    if (session_id() == '') {
        wfSetupSession();
        if (PONYDOCS_DEBUG) {
            error_log("DEBUG [" . __METHOD__ . "] started session");
        }
    }
    // Set selected product from URL
    if (preg_match('/^' . str_replace("/", "\\/", $wgScriptPath) . '\\/((index.php\\?title=)|)' . PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . '[\\/|:]{1}([' . PONYDOCS_PRODUCT_LEGALCHARS . ']+)[\\/|:]?/i', $_SERVER['PATH_INFO'], $match)) {
        PonyDocsProduct::SetSelectedProduct($match[3]);
    }
    // Set selected version from URL
    // - every time from /-separated title URLs
    // - only when no selected version already set from :-separated title
    $currentVersion = PonyDocsProductVersion::GetSelectedVersion(PonyDocsProduct::GetSelectedProduct(), FALSE);
    if (preg_match('/^' . str_replace("/", "\\/", $wgScriptPath) . '\\/((index.php\\?title=)|)' . PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . '\\/([' . PONYDOCS_PRODUCT_LEGALCHARS . ']+)\\/([' . PONYDOCS_PRODUCTVERSION_LEGALCHARS . ']+)/i', $_SERVER['PATH_INFO'], $match) || preg_match('/^' . str_replace("/", "\\/", $wgScriptPath) . '\\/((index.php\\?title=)|)' . PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . '\\/([' . PONYDOCS_PRODUCT_LEGALCHARS . ']+)\\/[' . PONYDOCS_PRODUCTMANUAL_LEGALCHARS . ']+TOC([' . PONYDOCS_PRODUCTVERSION_LEGALCHARS . ']+)/i', $_SERVER['PATH_INFO'], $match) || !isset($currentVersion) && preg_match('/^' . str_replace("/", "\\/", $wgScriptPath) . '\\/((index.php\\?title=)|)' . PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ':([' . PONYDOCS_PRODUCT_LEGALCHARS . ']+):[' . PONYDOCS_PRODUCTMANUAL_LEGALCHARS . ']+TOC([' . PONYDOCS_PRODUCTVERSION_LEGALCHARS . ']+)/i', $_SERVER['PATH_INFO'], $match) || !isset($currentVersion) && preg_match('/^' . str_replace("/", "\\/", $wgScriptPath) . '\\/((index.php\\?title=)|)' . PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ':([' . PONYDOCS_PRODUCT_LEGALCHARS . ']+):[' . PONYDOCS_PRODUCTMANUAL_LEGALCHARS . ']+:[^:]+:([' . PONYDOCS_PRODUCTVERSION_LEGALCHARS . ']+)/i', $_SERVER['PATH_INFO'], $match)) {
        $result = PonyDocsProductVersion::SetSelectedVersion($match[3], $match[4]);
        if (is_null($result)) {
            // this version isn't available to this user; go away
            $defaultRedirect = PonyDocsExtension::getDefaultUrl();
            if (PONYDOCS_DEBUG) {
                error_log("DEBUG [" . __METHOD__ . ":" . __LINE__ . "] redirecting to {$defaultRedirect}");
            }
            header("Location: " . $defaultRedirect);
            exit;
        }
    }
    PonyDocsWiki::getInstance(PonyDocsProduct::GetSelectedProduct());
}
예제 #3
0
 /**
  * Called when an unknown action occurs on url.  We are only interested in zipmanual action.
  */
 function onUnknownAction($action, $article)
 {
     global $wgOut, $wgUser, $wgTitle, $wgParser, $wgRequest;
     global $wgServer, $wgArticlePath, $wgScriptPath, $wgUploadPath, $wgUploadDirectory, $wgScript, $wgStylePath;
     // We don't do any processing unless it's zipmanual
     if ($action != 'zipmanual') {
         return true;
     }
     $zipAllowed = false;
     PonyDocsExtension::onUserCan($wgTitle, $wgUser, 'zipmanual', &$zipAllowed);
     if (!$zipAllowed) {
         error_log("WARNING [" . __METHOD__ . "] User attempted to perform a ZIP Export without permission.");
         $defaultRedirect = PonyDocsExtension::getDefaultUrl();
         header("Location: " . $defaultRedirect);
         exit;
     }
     // Get the title and make sure we're in Documentation namespace
     $title = $article->getTitle();
     if ($title->getNamespace() != NS_PONYDOCS) {
         return true;
     }
     // Grab parser options for the logged in user.
     $opt = ParserOptions::newFromUser($wgUser);
     // Any potential titles to exclude
     $exclude = array();
     // Determine articles to gather
     $articles = array();
     $pieces = explode(":", $wgTitle->__toString());
     // Try and get rid of the TOC portion of the title
     if (strpos($pieces[2], "TOC") && count($pieces) == 3) {
         $pieces[2] = substr($pieces[2], 0, strpos($pieces[2], "TOC"));
     } else {
         if (count($pieces) != 5) {
             // something is wrong, let's get out of here
             $defaultRedirect = PonyDocsExtension::getDefaultUrl();
             if (PONYDOCS_DEBUG) {
                 error_log("DEBUG [" . __METHOD__ . ":" . __LINE__ . "] redirecting to {$defaultRedirect}");
             }
             header("Location: " . $defaultRedirect);
             exit;
         }
     }
     $productName = $pieces[1];
     $ponydocs = PonyDocsWiki::getInstance($productName);
     $pProduct = PonyDocsProduct::GetProductByShortName($productName);
     if ($pProduct === NULL) {
         // product wasn't valid
         wfProfileOut(__METHOD__);
         $wgOut->setStatusCode(404);
         return FALSE;
     }
     $productLongName = $pProduct->getLongName();
     if (PonyDocsProductManual::isManual($productName, $pieces[2])) {
         $pManual = PonyDocsProductManual::GetManualByShortName($productName, $pieces[2]);
     }
     $versionText = PonyDocsProductVersion::GetSelectedVersion($productName);
     if (!empty($pManual)) {
         // We should always have a pManual, if we're printing
         // from a TOC
         $v = PonyDocsProductVersion::GetVersionByName($productName, $versionText);
         $toc = new PonyDocsTOC($pManual, $v, $pProduct);
         list($manualtoc, $tocprev, $tocnext, $tocstart) = $toc->loadContent();
         // We successfully got our table of contents.  It's
         // stored in $manualtoc
         foreach ($manualtoc as $tocEntry) {
             if ($tocEntry['level'] > 0 && strlen($tocEntry['title']) > 0) {
                 $title = Title::newFromText($tocEntry['title']);
                 $articles[$tocEntry['section']][] = array('title' => $title, 'text' => $tocEntry['text']);
             }
         }
     } else {
         error_log("WARNING [" . __METHOD__ . "] " . php_uname('n') . ": User attempted to export ZIP from a non TOC page with path:" . $wgTitle->__toString());
     }
     $html = self::getManualHTML($pProduct, $pManual, $v);
     $coverPageHTML = self::getCoverPageHTML($pProduct, $pManual, $v, false);
     // Make a temporary directory to store our archive contents.
     $tempDirPath = sys_get_temp_dir() . '/ponydocs-zip-export-' . time();
     $success = @mkdir($tempDirPath);
     if (!$success) {
         error_log("FATAL [" . __METHOD__ . "] Failed to create temporary directory " . $tempDirPath . " for Zip Export.");
         throw new Exception('Failed to create temporary directory for Zip Export.');
     }
     // Now, let's fetch all the img elements for both and grab them all in
     // parallel.
     $imgData = array();
     // Initialize our RollingCurl instance
     $rollingCurl = new \RollingCurl\RollingCurl();
     $mh = curl_multi_init();
     $manualDoc = new DOMDocument();
     @$manualDoc->loadHTML($html);
     $coverPageDoc = new DOMDocument();
     @$coverPageDoc->loadHTML($coverPageHTML);
     self::prepareImageRequests($manualDoc, $rollingCurl, $tempDirPath, &$imgData);
     self::prepareImageRequests($coverPageDoc, $rollingCurl, $tempDirPath, &$imgData);
     // Execute the RollingCurl requests
     $rollingCurl->execute();
     // Now update all our image elements in our appropriate DOMDocs.
     foreach ($imgData as $img) {
         // Put the data into it.
         file_put_contents($img['local_path'], $img['request']->getResponseText());
         // Modify element
         $img['element']->setAttribute('src', $img['new_path']);
         // Do curl cleanup
     }
     $html = $manualDoc->saveHTML();
     $coverPageHTML = $coverPageDoc->saveHTML();
     // Write the HTML to a tmp file
     $file = tempnam($tempDirPath, "zipexport-");
     $fh = fopen($file, 'w+');
     fwrite($fh, $html);
     fclose($fh);
     // Okay, write the title page
     $titlepagefile = tempnam($tempDirPath, "zipexport-");
     $fh = fopen($titlepagefile, 'w+');
     fwrite($fh, $coverPageHTML);
     fclose($fh);
     // Disable output of our standard mediawiki output.  We will be outputting a zip file instead.
     $wgOut->disable();
     // Create ZIP Archive which contains a cover and manual html
     $zip = new ZipArchive();
     $tempZipFilePath = tempnam($tempDirPath, "zipexport-");
     $zipFileName = $productName . '-' . $versionText . '-' . $pManual->getShortName() . '.zip';
     $zip->open($tempZipFilePath, ZipArchive::OVERWRITE);
     $zip->addFile($titlepagefile, 'cover.html');
     $zip->addFile($file, 'manual.html');
     // Iterate through all the images
     foreach ($imgData as $img) {
         $zip->addFile($img['local_path'], $img['new_path']);
     }
     $zip->close();
     header("Content-Type: application/zip");
     header("Content-Length: " . filesize($tempZipFilePath));
     header("Content-Disposition: attachment; filename=\"" . $zipFileName . "\"");
     readfile($tempZipFilePath);
     // Now remove all temp files
     self::rrmdir($tempDirPath);
     // Okay, let's add an entry to the error log to dictate someone requested a pdf
     error_log("INFO [" . __METHOD__ . "] " . php_uname('n') . ": zip export serve username=\"" . $wgUser->getName() . "\" version=\"{$versionText}\" " . " manual=\"" . $pManual->getShortName() . "\"");
     // No more processing
     return false;
 }
예제 #4
0
 /**
  * Called when an unknown action occurs on url.  We are only interested in pdfbook action.
  */
 function onUnknownAction($action, $article)
 {
     global $wgOut, $wgUser, $wgTitle, $wgParser, $wgRequest;
     global $wgServer, $wgArticlePath, $wgScriptPath, $wgUploadPath, $wgUploadDirectory, $wgScript, $wgStylePath;
     // We don't do any processing unless it's pdfbook
     if ($action != 'pdfbook') {
         return true;
     }
     // Get the title and make sure we're in Documentation namespace
     $title = $article->getTitle();
     if ($title->getNamespace() != NS_PONYDOCS) {
         return true;
     }
     // Grab parser options for the logged in user.
     $opt = ParserOptions::newFromUser($wgUser);
     // Log the export
     $msg = $wgUser->getUserPage()->getPrefixedText() . ' exported as a PonyDocs PDF Book';
     $log = new LogPage('ponydocspdfbook', false);
     $log->addEntry('book', $wgTitle, $msg);
     // Initialise PDF variables
     $layout = '--firstpage p1';
     $x_margin = '1.25in';
     $y_margin = '1in';
     $font = 'Arial';
     $size = '12';
     $linkcol = '4d9bb3';
     $levels = '2';
     $exclude = array();
     $width = '1024';
     $width = "--browserwidth 1024";
     // Determine articles to gather
     $articles = array();
     $pieces = explode(":", $wgTitle->__toString());
     // Try and get rid of the TOC portion of the title
     if (strpos($pieces[2], "TOC") && count($pieces) == 3) {
         $pieces[2] = substr($pieces[2], 0, strpos($pieces[2], "TOC"));
     } else {
         if (count($pieces) != 5) {
             // something is wrong, let's get out of here
             $defaultRedirect = PonyDocsExtension::getDefaultUrl();
             if (PONYDOCS_DEBUG) {
                 error_log("DEBUG [" . __METHOD__ . ":" . __LINE__ . "] redirecting to {$defaultRedirect}");
             }
             header("Location: " . $defaultRedirect);
             exit;
         }
     }
     $productName = $pieces[1];
     $ponydocs = PonyDocsWiki::getInstance($productName);
     $pProduct = PonyDocsProduct::GetProductByShortName($productName);
     if ($pProduct === NULL) {
         // product wasn't valid
         wfProfileOut(__METHOD__);
         $wgOut->setStatusCode(404);
         return FALSE;
     }
     $productLongName = $pProduct->getLongName();
     if (PonyDocsProductManual::isManual($productName, $pieces[2])) {
         $pManual = PonyDocsProductManual::GetManualByShortName($productName, $pieces[2]);
     }
     $versionText = PonyDocsProductVersion::GetSelectedVersion($productName);
     if (!empty($pManual)) {
         // We should always have a pManual, if we're printing from a TOC
         $v = PonyDocsProductVersion::GetVersionByName($productName, $versionText);
         // We have our version and our manual Check to see if a file already exists for this combination
         $pdfFileName = "{$wgUploadDirectory}/ponydocspdf-" . $productName . "-" . $versionText . "-" . $pManual->getShortName() . "-book.pdf";
         // Check first to see if this PDF has already been created and is up to date.  If so, serve it to the user and stop
         // execution.
         if (file_exists($pdfFileName)) {
             error_log("INFO [PonyDocsPdfBook::onUnknownAction] " . php_uname('n') . ": cache serve username=\"" . $wgUser->getName() . "\" product=\"" . $productName . "\" version=\"" . $versionText . "\" " . " manual=\"" . $pManual->getShortName() . "\"");
             PonyDocsPdfBook::servePdf($pdfFileName, $productName, $versionText, $pManual->getShortName());
             // No more processing
             return false;
         }
     } else {
         error_log("ERROR [PonyDocsPdfBook::onUnknownAction] " . php_uname('n') . ": User attempted to print a pdfbook from a non TOC page with path:" . $wgTitle->__toString());
     }
     $html = self::getManualHTML($pProduct, $pManual, $v);
     // HTMLDOC does not care for utf8.
     $html = utf8_decode("{$html}\n");
     // Write the HTML to a tmp file
     $file = "{$wgUploadDirectory}/" . uniqid('ponydocs-pdf-book');
     $fh = fopen($file, 'w+');
     fwrite($fh, $html);
     fclose($fh);
     // Okay, create the title page
     $titlepagefile = "{$wgUploadDirectory}/" . uniqid('ponydocs-pdf-book-title');
     $fh = fopen($titlepagefile, 'w+');
     $coverPageHTML = self::getCoverPageHTML($pProduct, $pManual, $v);
     fwrite($fh, $coverPageHTML);
     fclose($fh);
     $format = 'manual';
     /* @todo Modify so single topics can be printed in pdf */
     $footer = $format == 'single' ? '...' : '.1.';
     $toc = $format == 'single' ? '' : " --toclevels {$levels}";
     // Send the file to the client via htmldoc converter
     $wgOut->disable();
     $cmd = " --left {$x_margin} --right {$x_margin} --top {$y_margin} --bottom {$y_margin}";
     $cmd .= " --header ... --footer {$footer} --tocfooter .i. --quiet --jpeg --color";
     $cmd .= " --bodyfont {$font} --fontsize {$size} --linkstyle plain --linkcolor {$linkcol}";
     $cmd .= "{$toc} --format pdf14 {$layout} {$width} --titlefile {$titlepagefile} --size letter";
     $cmd = "htmldoc -t pdf --book --charset iso-8859-1 --no-numbered {$cmd} {$file} > {$pdfFileName}";
     putenv("HTMLDOC_NOCGI=1");
     $output = array();
     $returnVar = 1;
     exec($cmd, $output, $returnVar);
     if ($returnVar != 0) {
         // 0 is success
         error_log("INFO [PonyDocsPdfBook::onUnknownAction] " . php_uname('n') . ": Failed to run htmldoc (" . $returnVar . ") Output is as follows: " . implode("-", $output));
         print "Failed to create PDF.  Our team is looking into it.";
     }
     // Delete the htmlfile and title file from the filesystem.
     @unlink($file);
     if (file_exists($file)) {
         error_log("ERROR [PonyDocsPdfBook::onUnknownAction] " . php_uname('n') . ": Failed to delete temp file {$file}");
     }
     @unlink($titlepagefile);
     if (file_exists($titlepagefile)) {
         error_log("ERROR [PonyDocsPdfBook::onUnknownAction] " . php_uname('n') . ": Failed to delete temp file {$titlepagefile}");
     }
     // Okay, let's add an entry to the error log to dictate someone requested a pdf
     error_log("INFO [PonyDocsPdfBook::onUnknownAction] " . php_uname('n') . ": fresh serve username=\"" . $wgUser->getName() . "\" version=\"{$versionText}\" " . " manual=\"" . $pManual->getLongName() . "\"");
     PonyDocsPdfBook::servePdf($pdfFileName, $productName, $versionText, $pManual->getLongName());
     // No more processing
     return false;
 }