前回のプラグイン毎に詳細画面を持たせる拡張ポイントsoyshop.config.php

プラグイン毎に管理画面を持たせたらやりたいこととして、

プラグインの設定画面を設けることだろう。


前回、soyshop.config.phpのgetConfigPageメソッドで、

SOY2HTMLを活用して処理のPHPと表示のHTMLに切り分けつつ画面を表示したけれども、

SOY2HTMLで処理とデザインを切り分ける


更にSOY2HTMLでセキュアなフォームを設置したい。


というわけで、

今回はHTMLFormでトークンを導入してみることにする。




まずはサンプルコード

soyshop
└── webapp
    └── src
        └── module
            ├── features
            │   └── dummy_plugin
            │       └── module.ini
            └── plugins
                └── dummy_plugin
                    ├── config
                    │   ├── DummyPluginConfigPage.class.php
                    │   └── DummyPluginConfigPage.html
                    ├── soyshop.config.php
                    └── soyshop.info.php

上記の構成のダミープラグイン(ID:dummy_plugin)があったとする。


DummyPluignConfigPage.class.phpを読み込むために下記の記述があるsoyshop.config.phpを用意する。

soyshop.config.php

<?php

class DummyPluginConfig extends SOYShopConfigPageBase{

	/**
	 * @return string
	 */
	function getConfigPage(){
		SOY2::import("module.plugins.dummy_plugin.config.DummyPluginConfigPage");
		$form = SOY2HTMLFactory::createInstance("DummyPluginConfigPage");
		$form->setConfigObj($this);
		$form->execute();
		return $form->getObject();
	}

	/**
	 * @return string
	 */
	function getConfigPageTitle(){
		return "ダミープラグイン";
	}
}
SOYShopPlugin::extension("soyshop.config", "dummy_plugin", "DummyPluginConfig")

SOY2HTMLでDummyPluginConfigPageを読み込む時に、

$form->setConfigObj($this)でSOYShopConfigPageBaseを継承したクラスをセットしておくことが重要。


これらを踏まえた上で、SOY2HTML用のDummyPluginConfigPageを作成する。

DummyPluginConfigPage.class.php

<?php

class DummyPluginConfigPage extends WebPage {

	private $configObj;

	function __construct(){}

	function doPost(){
		if(soy2_check_token()){
			$this->configObj->redirect("updated");
		}
		$this->configObj->redirect("failed");
	}

	function execute(){
		parent::__construct();

		$this->addForm("form", array(
			"method" => "POST"
		));
	}

	function setConfigObj($configObj){
		$this->configObj = $configObj;
	}
}

表示に関するexecute内で

$this->createAdd("form", "HTMLForm", array(
	"method" => "POST"
));

を記述する。


今回は上記のコードの省略系である

$this->addForm("form", array(
	"method" => "POST"
));

を利用している。


説明は一旦置いといて、

上記の処理のPHPと対になるDummyPluginConfigPage.htmlを作成する。

DummyPluginConfigPage.html

<form soy:id="form">
	<input type="submit" value="押す">
</form>

<form>タグに属性としてsoy:id="form">を追加した上で、このプラグイン詳細画面を開いてみると、



押すボタンだけが表示された画面になりました。

注目すべきところはHTMLでソースコードを表示してみると、


<form action="/cms/soyshop/index.php/Config/Detail?plugin=dummy_plugin" method="POST">
	<input type="hidden" name="soy2_token" value="51d0c4be18a5916a5101379bbe84acf6" />
	<input type="submit" value="押す">
</form>

<form>タグのaction属性が自動生成されていることと、

soy2_tokenというname属性のhiddenのフォームが追加されています。


このsoy2_tokenの付与を踏まえた上で、再びDummyPluiginConfigPage.class.phpのdoPostメソッドを見て、


function doPost(){
	if(soy2_check_token()){
		$this->configObj->redirect("updated");
	}
	$this->configObj->redirect("failed");
}

if(soy2_check_token()){}をかますことで、

必ず今回のページからのPOST送信でないと処理を受け付けないということになり、

得体の知れないページからのPOST送信をすべて弾く。

SOY CMSに総当り攻撃を仕掛けてみる。その1


あとはsoyshop.config.phpでSOYShop_ConfigPageBaseを継承したクラスをSOY2HTML読み込み時に$configObjプロパティにセットしておいたので、

$configObjプロパティにredirectメソッドを持つことになったので、

$this->configObj->redirect("updated");のようなリダイレクト処理を行える。


あとは今回のページに設定用の各種フォームを設置し、

設定データの保存用の領域を用意する必要がある。


-続く-


追記

/common/lib/soy2_build.phpを開きclass HTMLFormでテキスト検索して

該当するクラスを読んでみる。


/* SOY2HTML/SOY2HTMLComponents/HTMLForm.class.php */
/**
 * @package SOY2.SOY2HTML
 */
class HTMLForm extends SOYBodyComponentBase{
	var $tag = "form";
	var $action;
	var $_method = "post";
	private $disabled;
	function setTag($tag){
		throw new SOY2HTMLException("[HTMLForm]タグの書き換えは不可です。");
	}
	function setMethod($method){
		$this->_method = $method;
	}
	function setAction($action){
		$this->action = $action;
	}
	function setTarget($target){
		$this->setAttribute("target",$target);
	}
	function getStartTag(){
		if(strtolower($this->_method) == "post"){
			$token = '<input type="hidden" name="soy2_token" value="<?php echo soy2_get_token(); ?>" />';
			return parent::getStartTag() . $token;
		}
		return parent::getStartTag();
	}
	function execute(){
		SOYBodyComponentBase::execute();
		if($this->action){
			$this->setAttribute("action",$this->action);
		}else{
			$this->setAttribute("action",@$_SERVER["REQUEST_URI"]);
		}
		$this->setAttribute('method',$this->_method);
		$disabled = ($this->disabled) ? "disabled" : null;
		$this->setAttribute("disabled",$disabled, false);
	}
	function setOnSubmit($value){
		if(!preg_match("/^javascript:/i",$value)){
			$value = "javascript:".$value;
		}
		$this->setAttribute("onsubmit",$value);
	}
	function getDisabled() {
		return $this->disabled;
	}
	function setDisabled($disabled) {
		$this->disabled = $disabled;
	}
}