PHP安全之数据过滤

在指南的开始,我们说过数据过滤在任何语言、任何平台上都是WEB应用安全的基石。这包含检验输入到应用的数据以及从应用输出的数据,而一个好的软件设计可以帮助开发人员做到:

确保数据过滤无法被绕过,确保不合法的信息不会影响合法的信息,并且识别数据的来源。

关于如何确保数据过滤无法被绕过有各种各样的观点,而其中的两种观点比其他更加通用并可提供更高级别的保障。
(更多…)

标签Tags:, , , , , , , , , , , , , , , , , , , , , , ,

Rsync详解

1、什么是Rsync

Rsync(remote synchronize)是一个远程数据同步工具,可通过LAN/WAN快速同步多台主机间的文件。Rsync使用所谓的“Rsync算法”来使本地和远程两个主机之间的文件达到同步,这个算法只传送两个文件的不同部分,而不是每次都整份传送,因此速度相当快。

  (更多…)

标签Tags:, , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,

PHP封装常用Javascript为JS类以便快速调用

<?php
# $Id: js..php,v 0.1 p $

// 禁止直接访问该页面
if (basename($HTTP__VARS['PHP_SELF']) == "js.class.php") {
     header("HTTP/1.0 404 Not Found");
}

# Purpose 封装了一些常用的Javascript代码,以便在PHP中快速调用

class JS{
     function JS(){}

     #返回上页
     # @param $step 返回的层数 默认为1
     function Back($step = -1){
         $msg = "history.go(".$step.");";
         JS::_Write($msg);
         JS::FreeResource();
         exit;
     }

    # 弹出警告的窗口
    # @param $msg 警告信息
     function Alert($msg){
         $msg = "alert(\"".$msg."\");";
         JS::_Write($msg);
     }

    # 写js
    # @param $msg
     function _Write($msg) {
         echo "<script language=\"\">\n";
         echo $msg;
         echo "\n</SCRIPT>";
     }

     # 刷新当前页
     function Reload(){
         $msg = "location.reload();";
         JS::FreeResource();
         JS::_Write($msg);
         exit;
     }

     #刷新弹出父页
     function ReloadOpener(){
         $msg = "if (opener)     opener.location.reload();";
         JS::_Write($msg);
     }

     #跳转到url
     #@param $ 目标页
     function Goto($url){
         $msg = "location.href = ‘$url’;";
         JS::FreeResource();
         JS::_Write($msg);
         exit;
     }

     #关闭窗口
     function Close(){
         $msg = "window.close()";
         JS::FreeResource();
         JS::_Write($msg);
         exit;
     }

     #
     #@param $frm 表单名
     function Submit($frm){
         $msg = $frm.".submit();";
         JS::_Write($msg);
     }

    #关闭数据库连接
    function FreeResource(){
         // 数据库连接标志
         global $conn;
         if (is_resource($conn))
             @_close($conn);
     }
}
?>

标签Tags:, , , , , , , , , , , , , , , , , , , ,

mysql优化及全文搜索

my.cnf文件常见优化模块
[mysqld]
port = 3306
-id = 1
socket = /tmp/mysql.sock

# 避免MySQL的外部锁定,减少出错几率增强稳定性。
skip-locking

# 禁止MySQL对外部连接进行DNS解析
skip-name-resolve

# 指定MySQL可能的连接数量
back_log = 256
(更多…)

标签Tags:, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,

图片轮换类,IE7、OP、FF、Chrome测试通过

<>
<head><>新闻图片轮换类</>
<script type=”text/”>
var fs = new FadeSlideClass();
fs.Width = 430;
fs.Height = 250;
fs.AddImage(“http://www.5bay.cn/Test/Image/001.jpg“, “#”, “新闻标题”);
fs.AddImage(“http://www.5bay.cn/Test/Image/002.jpg“, “#”, “新闻标题”);
fs.AddImage(“http://www.5bay.cn/Test/Image/003.jpg“, “//g.cn”, “去Google”);
fs.AddImage(“http://www.5bay.cn/Test/Image/004.jpg“, “#”, “新闻标题”);
fs.AddImage(“http://www.5bay.cn/Test/Image/005.jpg“, “#”, “新闻标题”);
fs.RenderTo(“divStage”);

/* 以下代码构造轮换类 */
function FadeSlideClass()
{
this.Width = 450;
this.Height = 300;
this.BorderColor = “#ddd”;
this.CurrentColor = “green”;
this.Delay = 5000;
var divContainer = document.createElement(“”);
var divImage = document.createElement(“div”);
var ulList = document.createElement(“ul”);
var me = this;
var arrImg = new Array;
this.Tag = divContainer;
this.AddImage = function(strImageUrl, strLink, strTitle)
{
   arrImg.push(arguments);
}
this.RenderTo = function(container)
{
   if(typeof container == “string”) container = document.getElementById(container) || container;
   if(typeof container == “string”) return setTimeout(function(){ me.RenderTo(container); }, 100);
   if(!arrImg.length) throw new Error(“尚未添加图片。”);
   var cssFloat = typeof ulList.style.cssFloat == “string” ? “cssFloat” : “styleFloat”;
   divContainer.style.width = this.Width + “px”;
   divContainer.style.height = this.Height + “px”;
   divImage.style.width = Math.round(this.Width * (arrImg.length – 1) / arrImg.length) + “px”;
   divImage.style.height = this.Height + “px”;
   divImage.style[cssFloat] = “left”;
   ulList.style.width = (this.Width – parseInt(divImage.style.width)) + “px”;
   ulList.style.height = this.Height + “px”;
   ulList.style.margin = “0px”;
   ulList.style.padding = “0px”;
   ulList.style[cssFloat] = “left”;
   divContainer.style.overflow = “hidden”;
   divImage.style.overflow = “hidden”;
   ulList.onmouseover = function(){ clearTimeout(me.Handler) };
   ulList.onmouseout = function(){ AutoPlay(); };
   InitImage(2);
   InitList(arrImg.length);
   container.appendChild(divContainer);
   divContainer.appendChild(divImage);
   divContainer.appendChild(ulList);
   LiMouseOver.call(ulList.firstChild);
   AutoPlay();
   this.AddImage = function(){ throw new Error(“该方法已过时。”); }
}
this.Display = function(imgThumb)
{
   var img = divImage.lastChild.lastChild;
   var opa = new OpacityClass(img);
   opa.Set(20);
   img.src = imgThumb.src;
   img.parentNode.href = imgThumb.parentNode.href;
   img.parentNode.title = imgThumb.parentNode.title;
   clearInterval(ulList.Handler);
   ulList.Handler = setInterval(function(){
    if(opa.Add(5) >= 100)
    {
     divImage.firstChild.lastChild.src = img.src;
     clearInterval(ulList.Handler);
    }
   }, 25);
}
function LiMouseOver()
{
   if(this == ulList.oldLi) return;
   if(ulList.oldLi) ulList.oldLi.style.borderColor = me.BorderColor;
   this.style.borderColor = me.CurrentColor;
   ulList.oldLi = this;
   me.Display(this.firstChild.firstChild);
}
function InitImage(count)
{
   if(–count) arguments.callee(count);
   var a = document.createElement(“a”);
   a.target = “_blank”;
   divImage.appendChild(a).style.position = “absolute”;
   var img = new Image;
   img.width = parseInt(divImage.style.width);
   img.height = me.Height;
   img.border = 0;
   if(!a.appendChild(img).filters) img.style.opacity = 1;
   else img.style.filter = “alpha(opacity=100)”;
}
function InitList(count)
{
   if(–count) InitList(count);
   var isIeNoDtd = document.compatMode != “CSS1Compat” && /msie/i.test(navigator.userAgent);
   var data = arrImg[count];
   var thumbWidth = parseInt(ulList.style.width);
   var thumbHeight = Math.round(me.Height / arrImg.length);
   var li = document.createElement(“li”);
   li.style.overflow = “hidden”;
   li.style.width = (isIeNoDtd ? thumbWidth : thumbWidth – 4) + “px”;
   li.style.height = (isIeNoDtd ? thumbHeight : thumbHeight – 4) + “px”;
   li.style.borderWidth = “2px”;
   li.style.borderStyle = “solid”;
   li.style.borderColor = me.BorderColor;
   var a = document.createElement(“a”);
   a.target = “_target”;
   a.href = data[1];
   a.title = data[2];
   var img = new Image;
   img.border = 0;
   img.width = thumbWidth;
   img.height = thumbHeight;
   img.src = data[0];
   img.style.verticalAlign = “top”;
   img.style.margin = “-2px”;
   a.appendChild(img);
   li.appendChild(a);
   li.style.listStyle = “none”;
   li.onmouseover = LiMouseOver;
   ulList.appendChild(li);
}
function AutoPlay()
{
   me.Handler = setTimeout(function()
   {
    LiMouseOver.call(ulList.oldLi.nextSibling || ulList.firstChild);
    AutoPlay();
   }, me.Delay);
}
function OpacityClass(tag)
{
   var isFilter = !!tag.filters;
   var obj = isFilter ? tag.filters.alpha : tag.style;
   this.Set = function(value)
   {
    obj.opacity = isFilter ? value : value / 100;
    return this;
   }
   this.Add = function(value)
   {
    var opa = isFilter ? obj.opacity : obj.opacity * 100;
    opa += value;
    if(opa > 100) opa = 100;
    obj.opacity = isFilter ? opa : opa / 100;
    return this;
   }
   this.valueOf = function()
   {
    return isFilter ? obj.opacity : obj.opacity * 100;
   }
}
}
</script>
</head>
<body>
<div id=”divStage”></div>
</body>
</html>

标签Tags:, , , , , , , , , , , , , , , ,

eAccelerator与memcache的区别与用途

eAccelerator和memcache,是目前较为主流的两个可使用在PHP之中的缓存加速工具.

eAccelerator专门为PHP开发,而memcache不仅仅用在PHP之中,其他所有的语言都可以使用.

 eAccelerator的主要功能:
   1. 缓存PHP文件的执行代码:在被缓存的代码再次被调用时,将直接从内存读取,从而在很大程度了PHP运行的速度.
   2. 提供了共享内存操作函数:用户可以将自己的常见非资源对像,保存到内存之中,并可以随时读取出来.

 memcache的主要功能:
 提供共享内存操作函数,可以保存和读取数据

 两者的共同点:
 共同点:都提供了共享内存操作函数,可以用来保存和读取自己的数据

 两者的区别:
 eAccelerator作为PHP的扩展库存在,那么仅在PHP运行时,可以操作和读写共享内存,一般情况,只能由操作共享内存的程序自己调用.
 同时,eAccelerator可以缓存PHP程序的执行代码,提升程序的调入和执行速度.
 memcache主要作为一个共享内存服务器,其PHP扩展库仅仅作为PHP到memcache的连接库存在,类似MySQL扩展库.因而,memcache可以完全脱离PHP,其共享的数据,可以被不同的程序调用.

 根据两者的不同,我们将他们使用在真真需要的地方:
 eAccelerator主要用于单机PHP提速,缓存中间数据.对于实时性高,但数据操作量小的情况下,非常实用.
 memcache用于分布式或者集群系统,多台服务器可以共享数据.对于实时性高,同时数据操作量大的情况下,非常实用.

标签Tags:, , , , , , , , , , , , , ,

PHP中的Memcache函数库(Memcache Functions)

/usr/local/bin/memcached -d -m 10 -u root -l 127.0.0.1 -p 11211 -c 256 -P /tmp/memcached.pid
memcached 的服务正式启动

Memcache::add — 添加一个值,如果已经存在,则返回false
Memcache::addServer — 添加一个可供使用的服务器地址
Memcache::close — 关闭一个Memcache对象
Memcache::connect — 创建一个Memcache对象
memcache_debug — 控制调试功能
Memcache::decrement — 对保存的某个key中的值进行减法操作
Memcache::delete — 删除一个key值
Memcache::flush — 清除所有缓存的数据
Memcache::get — 获取一个key值
Memcache::getExtendedStats — 获取进程池中所有进程的运行系统统计
Memcache::getServerStatus — 获取运行服务器的参数
Memcache::getStats — 返回服务器的一些运行统计信息
Memcache::getVersion — 返回运行的Memcache的版本信息
Memcache::increment — 对保存的某个key中的值进行加法操作
Memcache::pconnect — 创建一个Memcache的持久连接对象
Memcache::replace — R对一个已有的key进行覆写操作
Memcache::set — 添加一个值,如果已经存在,则覆写
Memcache::setCompressThreshold — 对大于某一大小的数据进行压缩
Memcache::setServerParams — 在运行时修改服务器的参数 (更多…)

标签Tags:, , , , , , , , , , , , , , , , , , , ,

用四叉树管理散布在平面上的对象

周末一直在考虑怎样在游戏服务器中保存和管理那些有平面坐标的对象。希望能方便的查到每个对象附近的东西。以往用过的方法是给(平面)场景打上格子,然后再把每个对象放入相应的格子中。

这次又遇到这个问题,却不想用网格的方法来解决问题了。

原因主要是这么几点:一,用网格对于大场景特别消耗内存,而且不太适合做无限延展的场景。二,查询每个对象周围的东西时,不太方便。格子的粒度越小,速度越慢。

虽然这两个问题,都可以通过改进算法来回避。不过这次,我想尝试一下用四叉树解决这个问题。

用四叉树的话,内存占用量应该 O(n) 。如果定死了四叉树的扩展深度,可以推算出节点的最大可能消耗量。我想,如果只是为了解决 AOI 的计算,5 级深度已经足够。这样,大约预分配出 20 * n 个节点,几乎肯定够用了。

我希望场景是从坐标原点向四周无限延展开,没有什么具体的尺寸限制。所以,这次实现的时候对四叉树做了改造。第一级的划分是一个特例,它将平面分成四块,每一块都可以向某个方向无限延伸。
(更多…)

标签Tags:, , , , , , , , ,

数据服务器的设计

今天开始正式开始做数据服务器。在这点上,我希望一组服务器上所有的逻辑服务遇到的数据存取需求都通过一个单一的数据服务器完成。而且,写入数据是单向通讯的。即,逻辑服务器只提读写盘请求,而无须确认。写数据好说,读数据稍微难处理一点,我现在的方案是,数据服务器加载数据的部分只对位置服务器负责,把数据提交到位置服务器即可。位置服务器可以通过分析数据知道玩家的数据流应该流向哪台逻辑服务器。

以上逻辑是基于每个玩家有独立的数据的,而且一个玩家同时只存在于唯一一个场景。也就是说,当一组数据存活的时候,只唯一属于一台逻辑服务器。这样做的好处是,切换场景非常的简单,只是让玩家从一个场景退出,给数据服务器发出写盘指令,并发送所有数据。数据服务器写盘的同时也 了这些数据,并向位置服务器提交新的位置,并把这些数据转发向位置服务器。位置服务器可以再转交给新的场景。

对于玩家登陆和登出的处理并没有特别之处,我们可以设立两个虚拟场景,一个负责登入,一个负责登出。每个新连接自动导入登入场景,这个场景负责发出加载指令(下面可以看到,甚至无须设置加载数据的协议)。然后再做一个自动的场景切换操作即可。而玩家登出,则是转入登出场景,这是一个黑洞,玩家的连接可以在这里安全的断掉。

当玩家不停的穿梭于各个场景之间时,为了避免频繁的数据转发,我们可以给玩家数据做一个赃标记。如果没有弄赃,实际的数据可以不被转发。这个标记的另一个意义在于,若数据没有弄赃,而数据服务器的 cache 中又没有数据时,就需要从外存加载了。其实这就是一个读请求。 (更多…)

标签Tags:, , , , , , , , , , ,

多进程的游戏服务器设计

目前,我们的游戏服务器组是按多进程的方式设计的。强调多进程,是想提另外一点,我们每个进程上是单线程的。所以,我们在设计中,系统的复杂点在于进程间如何交换数据;而不需要考虑线程间的数据锁问题。

如果肆意的做进程间通讯,在进程数量不断增加后,会使系统混乱不可控。经过分析后,我决定做如下的限制:

如果一个进程需要和多个服务器做双向通讯,那么这个进程不能处理复杂的逻辑,而只是过滤和转发数据用。即,这样的一个进程 S ,只会把进程 A 发过来的数据转发到 B ;或把进程 B 发过来的数据转发到 A 。或者从一端发过来的数据,经过简单的协议分析后,可以分发到不同的地方。例如,把客户端发过来的数据包中的聊天信息分离处理,交到聊天进程处理。

有逻辑处理的进程上的数据流一定是单向的,它可以从多个数据源读取数据,但是处理后一定反馈到另外的地方,而不需要和数据源做逻辑上的交互。

每个进程尽可能的保持单个输入点,或是单个输出点。

所有费时的操作均发到独立的进程,以队列方式处理。

按功能和场景划分进程,单一服务和单一场景中不再分离出多个进程做负载均衡。 (更多…)

标签Tags:, , , , , , , , , , ,