现在的位置: 首页 > 编程语言 > 正文

构建可配置PHP应用程序有哪些方式

2020年05月28日 编程语言 ⁄ 共 7593字 ⁄ 字号 评论关闭

  如果计划让其他人或公司可以使用您的PHP应用程序,需要确保该程序是可配置的。至少,要允许用户以一种安全的方式设置数据库登录及密码,从而使其中的材料不会对外公开。下面学步园小编来讲解下构建可配置PHP应用程序有哪些方式?

  构建可配置PHP应用程序有哪些方式

  使用INI文件进行配置

  PHP内建了对配置文件的支持。这是通过php.ini文件这样的初始化文件(INI)机制实现的,在php.ini文件中定义了数据库连接超时或会话如何存储等常量。如果愿意的话,可以在这个php.ini文件中为应用程序定制配置。为了说明,我将下列代码行添加到php.ini文件中。

  myapptempdir=foo

  然后,我编写了一个小PHP脚本来读取这个配置项,如清单1所示。

  清单1.ini1.php

  

  functionget_template_directory()

  {

  $v=get_cfg_var("myapptempdir");

  return($v==null)?"tempdir":$v;

  }

  echo(get_template_directory()."\n");

  ?>

  当在命令行中运行这段代码时,得到如下结果:

  %phpini1.php

  foo

  %

  太棒了。但为什么不能用标准的INI函数来获取myapptempdir配置项的值呢?我研究了一下,发现在大多数情况下,定制配置项不能使用这些方法来获取。然而,使用get_cfg_var函数却是可以访问的。

  为使这个方法更加简单,将对变量的访问封装在第二个函数中,该函数使用配置键名及一个缺省值作为参数,如下所示。

  清单2.ini2.php

  functionget_ini_value($n,$dv)

  {

  $c=get_cfg_var($n);

  return($c==null)?$dv:$c;

  }

  functionget_template_directory()

  {

  returnget_ini_value("myapptempdir","tempdir");

  }

  这是对如何访问INI文件的一个很好的概括,所以,如果要使用一个不同的机制或将这个INI文件存储到其他位置,就不需要为更改大量的函数而大费周折。

  我不推荐使用INI文件作为应用程序的配置,这有两个理由。首先,虽然这样做较容易读取INI文件,但却几乎不可能安全地写INI文件。所以这样做只适合于只读配置项。第二,php.ini文件在服务器的所有应用程序上共享,所以我认为特定于应用程序的配置项不应该写在该文件中。

  需要对INI文件了解什么呢?最重要的是如何重置include路径来添加配置项,如下所示。

  清单3.ini3.php

  

  echo(ini_get("include_path")."\n");

  ini_set("include_path",

  ini_get("include_path").":./mylib");

  echo(ini_get("include_path")."\n");

  ?>

  在本例中,我将我的本地mylib目录添加到了include路径中,所以能够从该目录中requirePHP文件,而不需要将该路径添加到require语句中。

  PHP中的配置

  通常对于在INI文件中存储配置条目的一个替代办法是使用一个简单的PHP脚本来保持数据。如下是一个样例。

  清单4.config.php

  

  #Specifythelocationofthetemporarydirectory

  #

  $TEMPLATE_DIRECTORY="tempdir";

  ?>

  使用该常量的代码如下所示。

  清单5.php.php

  

  require_once'config.php';

  functionget_template_directory()

  {

  global$TEMPLATE_DIRECTORY;

  return$TEMPLATE_DIRECTORY;

  }

  echo(get_template_directory()."\n");

  ?>

  该代码首先包含配置文件(config.php),接着就可以直接使用这些常量了。

  使用这项技术有很多优势。首先,如果某些人仅仅浏览config.php文件,该页面是空白的。所以可以将config.php放到相同的文件中,并作为Web应用程序的根。第二,在任何编辑器中都可编辑,并且在一些编辑器中甚至具备语法着色及语法检查功能。

  这项技术的缺点是,这是一个像INI文件一样的只读技术。将数据从此文件中提取出来是轻而易举的,但在该PHP文件中调整数据却很困难,在一些情况下甚至是不可能的。

  下面的替代方法显示了如何编写在本质上既可读又可写的配置系统。

  文本文件

  前面的两个例子对于只读配置条目都是合适的,但对于既读又写的配置参数来说又如何呢?首先,看看清单6中的文本配置文件。

  清单6.config.txt

  #Myapplication'sconfigurationfile

  Title=MyApp

  TemplateDirectory=tempdir

  这是同INI文件相同的文件格式,但我自己编写了辅助工具。为此,我创建了自己的Configuration类,如下所示。

  清单7.text1.php

  

  classConfiguration

  {

  private$configFile='config.txt';

  private$items=array();

  function__construct(){$this->parse();}

  function__get($id){return$this->items[$id];}

  functionparse()

  {

  $fh=fopen($this->configFile,'r');

  while($l=fgets($fh))

  {

  if(preg_match('/^#/',$l)==false)

  {

  preg_match('/^(.*?)=(.*?)$/',$l,$found);

  $this->items[$found[1]]=$found[2];

  }

  }

  fclose($fh);

  }

  }

  $c=newConfiguration();

  echo($c->TemplateDirectory."\n");

  ?>

  该代码首先创建了一个Configuration对象。该构造函数接下来读取config.txt并用解析过的文件内容来设置局部变量$items。

  该脚本随后寻找TemplateDirectory,这并没有在对象中直接定义。因此,使用设置成'TemplateDirectory'的$id来调用神奇的__get方法,__get方法针对该键返回$items数组中的值。

  这个__get方法特定于PHPV5环境,所以此脚本必须在PHPV5下运行。实际上,本文中所有的脚本都需要在PHPV5下运行。

  当在命令行运行此脚本时,能看到下列结果:

  %phptext1.php

  tempdir

  %

  一切都在预料之中,该对象读取config.txt文件,然后为TemplateDirectory配置项获得正确的值。

  但对于设置一个配置值,应该怎么做呢?在此类中建立一个新方法及一些新的测试代码,就能够得到这个功能,如下所示。

  清单8.text2.php

  

  classConfiguration

  {

  ...

  function__get($id){return$this->items[$id];}

  function__set($id,$v){$this->items[$id]=$v;}

  functionparse(){...}

  }

  $c=newConfiguration();

  echo($c->TemplateDirectory."\n");

  $c->TemplateDirectory='foobar';

  echo($c->TemplateDirectory."\n");

  ?>

  现在,有了一个__set函数,它是__get函数的“堂兄弟”。该函数并不为一个成员变量获取值,当要设置一个成员变量时,才调用这个函数。底部的测试代码设置值并打印出新值。

  下面是在命令行中运行此代码时出现的结果:

  %phptext2.php

  tempdir

  foobar

  %

  太好了!但如何能将它存储到文件中,从而将使这个改动固定下来呢?为此,需要写文件并读取它。用于写文件的新函数,如下所示。

  清单9.text3.php

  

  classConfiguration

  {

  ...

  functionsave()

  {

  $nf='';

  $fh=fopen($this->configFile,'r');

  while($l=fgets($fh))

  {

  if(preg_match('/^#/',$l)==false)

  {

  preg_match('/^(.*?)=(.*?)$/',$l,$found);

  $nf.=$found[1]."=".$this->items[$found[1]]."\n";

  }

  else

  {

  $nf.=$l;

  }

  }

  fclose($fh);

  copy($this->configFile,$this->configFile.'.bak');

  $fh=fopen($this->configFile,'w');

  fwrite($fh,$nf);

  fclose($fh);

  }

  }

  $c=newConfiguration();

  echo($c->TemplateDirectory."\n");

  $c->TemplateDirectory='foobar';

  echo($c->TemplateDirectory."\n");

  $c->save();

  ?>

  新的save函数巧妙地操作config.txt。我并没有仅用更新过的配置项重写文件(这样会移除掉注释),而是读取了这个文件并灵活地重写了$items数组中的内容。这样的话,就保留了文件中的注释。

  在命令行运行该脚本并输出文本配置文件中的内容,能够看到下列输出。

  清单10.保存函数输出

  %phptext3.php

  tempdir

  foobar

  %catconfig.txt

  #Myapplication'sconfigurationfile

  Title=MyApp

  TemplateDirectory=foobar

  %

  构建可配置PHP应用程序有哪些方式

  原始的config.txt文件现在被新值更新了。

  XML配置文件

  尽管文本文件易于阅读及编辑,但却不如XML文件流行。另外,XML有众多适用的编辑器,这些编辑器能够理解标记、特殊符号转义等等。所以配置文件的XML版本会是什么样的呢?清单11显示了XML格式的配置文件。

  清单11.config.xml

  

  

  

  tempdir

  

  清单12显示了使用XML来装载配置设置的Configuration类的更新版。

  清单12.xml1.php

  

  classConfiguration

  {

  private$configFile='config.xml';

  private$items=array();

  function__construct(){$this->parse();}

  function__get($id){return$this->items[$id];}

  functionparse()

  {

  $doc=newDOMDocument();

  $doc->load($this->configFile);

  $cn=$doc->getElementsByTagName("config");

  $nodes=$cn->item(0)->getElementsByTagName("*");

  foreach($nodesas$node)

  $this->items[$node->nodeName]=$node->nodeValue;

  }

  }

  $c=newConfiguration();

  echo($c->TemplateDirectory."\n");

  ?>

  看起来XML还有另一个好处:代码比文本版的代码更为简洁、容易。为保存这个XML,需要另一个版本的save函数,将结果保存为XML格式,而不是文本格式。

  清单13.xml2.php

  ...

  functionsave()

  {

  $doc=newDOMDocument();

  $doc->formatOutput=true;

  $r=$doc->createElement("config");

  $doc->appendChild($r);

  foreach($this->itemsas$k=>$v)

  {

  $kn=$doc->createElement($k);

  $kn->appendChild($doc->createTextNode($v));

  $r->appendChild($kn);

  }

  copy($this->configFile,$this->configFile.'.bak');

  $doc->save($this->configFile);

  }

  ...

  这段代码创建了一个新的XML文档对象模型(DocumentObjectModel,DOM),然后将$items数组中的所有数据都保存到这个模型中。完成这些以后,使用save方法将XML保存为一个文件。

  使用数据库

  最后的替代方式是使用一个数据库保存配置元素的值。那首先要用一个简单的模式来存储配置数据。下面是一个简单的模式。

  清单14.schema.sql

  DROPTABLEIFEXISTSsettings;

  CREATETABLEsettings(

  idMEDIUMINTNOTNULLAUTO_INCREMENT,

  nameTEXT,

  valueTEXT,

  PRIMARYKEY(id)

  );

  这要求进行一些基于应用程序需求的调整。例如,如果想让配置元素按照每个用户进行存储,就需要添加用户ID作为额外的一列。

  为了读取及写入数据,我编写了如图15所示的更新过的Configuration类。

  清单15.db1.php

  

  require_once('DB.php');

  $dsn='mysql://root:password@localhost/config';

  $db=&DB::Connect($dsn,array());

  if(PEAR::isError($db)){die($db->getMessage());}

  classConfiguration

  {

  private$configFile='config.xml';

  private$items=array();

  function__construct(){$this->parse();}

  function__get($id){return$this->items[$id];}

  function__set($id,$v)

  {

  global$db;

  $this->items[$id]=$v;

  $sth1=$db->prepare('DELETEFROMsettingsWHEREname=?');

  $db->execute($sth1,$id);

  if(PEAR::isError($db)){die($db->getMessage());}

  $sth2=$db->prepare('INSERTINTOsettings(id,name,value)VALUES(0,?,?)');

  $db->execute($sth2,array($id,$v));

  if(PEAR::isError($db)){die($db->getMessage());}

  }

  functionparse()

  {

  global$db;

  $doc=newDOMDocument();

  $doc->load($this->configFile);

  $cn=$doc->getElementsByTagName("config");

  $nodes=$cn->item(0)->getElementsByTagName("*");

  foreach($nodesas$node)

  $this->items[$node->nodeName]=$node->nodeValue;

  $res=$db->query('SELECTname,valueFROMsettings');

  if(PEAR::isError($db)){die($db->getMessage());}

  while($res->fetchInto($row)){

  $this->items[$row[0]]=$row[1];

  }

  }

  }

  $c=newConfiguration();

  echo($c->TemplateDirectory."\n");

  $c->TemplateDirectory='newfoo';

  echo($c->TemplateDirectory."\n");

  ?>

  这实际上是一个混合的文本/数据库解决方案。请仔细观察parse方法。该类首先读取文本文件来获取初始值,然后读取数据库,进而将键更新为最新的值。在设置一个值后,键就从数据库中移除掉,并添加一条具有更新过的值的新记录。

  观察Configuration类如何通过本文的多个版本来发挥作用是一件有趣的事,该类能从文本文件、XML及数据库中读取数据,并一直保持相同的接口。我鼓励您在开发中也使用具有相同稳定性的接口。对于对象的客户机来说,这项工作具体是如何运行的是不明确的。关键的是对象与客户机之间的契约。

  以上就是关于“构建可配置PHP应用程序有哪些方式”的内容,希望对大家有用。更多资讯请关注学步园。学步园,您学习IT技术的优质平台!

抱歉!评论已关闭.