当前位置

突破:在MediaWiki页面中嵌入PHP程序

James Qi 在 2011年5月7日 - 19:34 提交
内容摘要:摆弄MediaWiki好几年了,都尽量避免碰PHP程序,在不得已的情况下,对皮肤文件、少数配置参数等地方进行过有限的修改。去年底开始尝试改用Drupal系统,不可避免遇到需要修改PHP程序的地方,经过......

  摆弄MediaWiki好几年了,都尽量避免碰PHP程序,在不得已的情况下,对皮肤文件、少数配置参数等地方进行过有限的修改。去年底开始尝试改用Drupal系统,不可避免遇到需要修改PHP程序的地方,经过一段时间的摸索,发现PHP也不是想象中的那么难,不过是另一种程序语言而已,要精通不容易,但上手还是不太难的。

  在Drupal中调用PHP程序摸出一些门道后,想到以前使用MediaWiki平台搭建的查号吧网站中一直没有解决的一个问题,就是包含10000个号码列表的页面,因为采用Wiki代码而速度极慢,新页面的生成需要数十秒的时间,当大量更新模板的时候,3台16核CPU的服务器处理起来都需要好些天,以前也想过用PHP程序来实现,但一直没有实际尝试。

  今天下午去MediaWiki官方网站找到了一个可以在页面中嵌入PHP程序的扩展: Extension:Include PHP ,搭建起来比较简单,就按照说明中操作就可以,然后写了一个很简单的多重循环程序:

<?php
$title = str_replace("/","",strrchr(urldecode($_SERVER["REQUEST_URI"]),"/"));
for ($i=0; $i<=9; $i++)
{
 echo "\n<h2>".$title.$i.":".$title.$i."000-".$title.$i."999"."</h2>\n\n";
 for ($j=0; $j<=9; $j++)
 {
  echo "\n<h3>".$title.$i.$j.":".$title.$i.$j."00-".$title.$i.$j."99"."</h3>\n\n";
  for ($k=0; $k<=9; $k++)
  {
   echo "<p>".$title.$i.$j.$k.":";
   echo $title.$i.$j.$k."0,";
   echo $title.$i.$j.$k."1,";
   echo $title.$i.$j.$k."2,";
   echo $title.$i.$j.$k."3,";
   echo $title.$i.$j.$k."4,";
   echo $title.$i.$j.$k."5,";
   echo $title.$i.$j.$k."6,";
   echo $title.$i.$j.$k."7,";
   echo $title.$i.$j.$k."8,";
   echo $title.$i.$j.$k."9</p>\n";
  }
 }
}
?>

  就解决了这个困扰几年的麻烦,以前需要数十秒生成的页面现在只要零点几秒甚至零点零几秒就可以处理了,速度提高了数百倍以上!

  有几点需要注意的地方:

  • 扩展程序中包含了两处“$parser->disableCache();”,如果还是希望有缓存的话,可以注释掉;
  • 扩展程序有用户组安全机制,如果希望各种用户保存的页面都能调用设定的PHP程序,可以在LocalSettings.php中设置“$wgGroupPermissions['*']['scripting'] = true;”。

  在MediaWiki页面中嵌入PHP程序算是一种新突破,推广开来还可以解决以前一直希望达到的目的,例如:页面下方嵌入留言框,调用API等。不过现在其它事情太忙,以后再说吧。


  2015年4月补充:上面这个MediaWiki的扩展程序因为安全性问题,很早就被从官方网站删除了,也更找不到升级版本了。要想实现更灵活的嵌入内容,可以《尝试编写MediaWiki的扩展程序》,这是最正规可靠的办法,多尝试一下后应该也不是很难。

自由标签:

评论

-- 发自IP地址: 192.168.0.133 (位置 | 谁是)

不客气,有技术问题多共享、多交流,我也是从别人的文章中学到很多,希望自己的一些记录也能帮得上别人。

James Qi / 祁劲松

-- 发自IP地址: 59.172.48.92 (位置 | 谁是)

<?php
if (!defined ('MEDIAWIKI')) {
  echo 'This is a MediaWiki-Extension and not meant to be run standalone!';
  exit (1);
}

$wgExtensionCredits['parserhook'] [] = array (
  'name'             => 'include_PHP',
  'author'           => 'Jannis Achstetter',
  'url'              => '
  'description'      => 'Allows you to include PHP-files that are executed and their output shown on the wiki-page',                                                                      
  'version'          => 2,                                                                                                                                                                
  'path'             => __FILE__,                                                                                                                                                         
);                                                                                                                                                                                        

// We register our function "include_PHPParserHook" to the tag <include_PHP />                                                                                                            
// A filename of a file to be included must be given. For example:                                                                                                                        
// <include_PHP file="phpinfo" />                                                                                                                                                         
// Files are searched in the "$IP/scripting"-folder and have the .php-extension.                                                                                                          
// This extension must not be given with the file=-parameter; it is appended                                                                                                              
//                                                                                                                                                                                        
// We parse the PHP in the "include_PHPParserHook"-function. The resulting text                                                                                                           
// is not yet returned to the Wiki-page, only a marker is placed there. The                                                                                                               
// output it stored in the array $markerList.                                                                                                                                             
// In the "include_PHPParserAfterTidy"-function, the markers are replaced by
// the real output. This way, we can output HTML that is not touched by
// MediaWiki's parser.

$wgHooks['ParserAfterTidy'][] = 'include_PHPParserAfterTidy';
$wgHooks['ParserFirstCallInit'][] = 'include_PHPSetup';

function include_PHPSetup (&$parser) {
  $parser->setHook( 'include_PHP', 'include_PHPParserHook' );
  return true;
}

$markerList = array();
function include_PHPParserHook ($input, $argv, $parser) {
  global $markerList;

  // Disable page caching since the PHP-output is dynamic
//jamesqi 2011-5-7  $parser->disableCache();

  // Sanity checking: allow execution only if the currently viewed Revision
  // was created/edited by a user with the "scripting"-permission
  $user = User::newFromName ($parser->getRevisionUser());
  $user->load();
  if (!$user->isAllowed ('scripting')) {
    $output = 'include_PHP: The revision you are viewing was created by a user that does not have the permissions to include PHP code! I won\'t execute that!';
  } else {
    // No file-parameter has been given! Nothing to do for us :)
    if (!array_key_exists("file", $argv)) {
      $output = 'include_PHP: No script-file to be included given!';
    } else {
      // Check for evil directory traversal (alias "../")-attacks
      // note the 3 "="-signs in the comparison!
      if (!(strpos($argv['file'], '../') === FALSE)) {
        $output = 'include_PHP: Possible directory-traversal attack! Why do you have "../" in the filename?';
      } else {
        // A file-parameter has been given! Check if it exists and is readable
        if (!is_readable('scripting/'.$argv['file'].'.php')) {
          $output = 'include_PHP: File to be included does not exist!';
        } else {
          // Actual parsing is done here!
          // Use ob_start so things like phpinfo() put their output inside the wiki-page "body-text", not on top of it
          ob_start();
          include('scripting/'.$argv['file'].'.php');
          $output = trim(ob_get_clean());
        }
      }
    }
  }

  // Get a new marker, store the output there and
  // insert it's name onto the (yet to be parsed) page
  $markercount = count($markerList);
  $marker = "xy-include_PHP-marker-".$markercount."-xy";

  global $include_PHP_override_marker;
  if ($include_PHP_override_marker) {
    $markerList[$markercount] = $include_PHP_override_marker;
  } else {
    $markerList[$markercount] = $output;
  }
  return $marker;
}

// find markers in $text
// replace markers with actual output
function include_PHPParserAfterTidy ($parser, &$text) {
  global $markerList;

  // Disable page caching since the PHP-output is dynamic
//jamesqi2011-5-7  $parser->disableCache();

  $keys = array();
  $marker_count = count($markerList);

  for ($i = 0; $i < $marker_count; $i++) {
    $keys[] = 'xy-include_PHP-marker-'.$i.'-xy';
  }

  $text = str_replace($keys, $markerList, $text);
  return true;
}
?>

James Qi / 祁劲松