php - Zend_Validate_Db_RecordExists 排除逻辑问题

标签 php zend-framework zend-validate

我有一份工作申请表,管理员需要从某些用户 ID 列表中进行选择。该列表仅包含“雇主”类型的用户 ID,但是我想验证管理员输入,因此如果他手动插入不存在的 ID 或者与“雇主”类型不同的用户的 ID,则验证应该失败。我认为执行此操作的代码是:

new Zend_Validate_Db_RecordExists(
    array(
        'table' => 'users',
        'field' => 'id',
        'exclude' => "mode != 'employer'"
    )
)

所以,我正在搜索表 users 中的所有记录,不包括那些 mode != 'employer' 的记录 - 如果存在这样的记录,其中 id 等于从输入中选取的记录,则它通过验证。但是,上面的代码不起作用 - 我必须执行 'exclude' => "mode = 'employer'",因此排除实际上等于 where 语句。我对这里逻辑的理解是错误的 - 有人能告诉我为什么吗?

PHP:5.2.17,Zend:1.10.4

编辑:(对@ro ko询问的评论,因为它可能会澄清事情)

请在此处找到表格和示例代码:http://pastebin.com/C7AXMNTZ 。根据我的理解,这应该对 Joker(是雇主)返回有效,但对 Kingpin(不是雇主)和 Poison Ivy(不在数据库中)返回 false - 正如你所看到的结果不是我所期望的。

最佳答案

A) '排除'=>“模式!='雇主'”

    $id = new Zend_Form_Element_Select("id");
    $id->setRegisterInArrayValidator(false);
    $id->addValidator(new Zend_Validate_Db_RecordExists(array(
        'table' => 'villains',
        'field' => 'id',
        'exclude' => "mode != 'employer'"
    )));

产生以下查询:

SELECT `villains`.`id` 
    FROM `villains` 
    WHERE (`id` = :value) AND (mode != 'employer') 
    LIMIT 1

B) '排除'=>“模式='雇主'”

    $id = new Zend_Form_Element_Select("id");
    $id->setRegisterInArrayValidator(false);
    $id->addValidator(new Zend_Validate_Db_RecordExists(array(
        'table' => 'villains',
        'field' => 'id',
        'exclude' => "mode = 'employer'"
    )));

产生以下查询:

SELECT `villains`.`id` 
    FROM `villains` 
    WHERE (`id` = :value) AND (mode = 'employer') 
    LIMIT 1

C) 'exclude' => array("field"=> "mode", "value"=> "employer")

    $id = new Zend_Form_Element_Select("id");
    $id->setRegisterInArrayValidator(false);
    $id->addValidator(new Zend_Validate_Db_RecordExists(array(
        'table' => 'villains',
        'field' => 'id',
        'exclude' => array(
            "field" => "mode",
            "value" => "employer"
        )
    )));

产生以下查询:

SELECT `villains`.`id` 
    FROM `villains` 
    WHERE (`id` = :value) AND (`mode` != 'employer') 
    LIMIT 1

结果

你想要B。它令人困惑,并且可以说组件的逻辑和行为是倒退的。尽管如此,您想要的行为来自示例 B。

附录

我们可以进行一个测试(我的意思是一起进行黑客攻击)来检查上述内容是否按预期工作。

test1 和 test2 都通过了,但是正如您从提供程序中看到的那样,它们都产生不同的结果。

class SO14706653Test extends PHPUnit_Framework_TestCase
{
    /**
     * @var Zend_Test_PHPUnit_Db_Connection
     */
    public $dbConnection;

    public function getRowCount($tableName) {
        $query = "SELECT COUNT(*) FROM ".$this->dbConnection->quoteSchemaObject($tableName);
        return (int) $this->dbConnection->getConnection()->query($query)->fetchColumn();
    }

    // hack a very quick setup for tests
    public function setup() {
        $app = new Zend_Application(APPLICATION_ENV, APPLICATION_PATH . '/configs/application.ini');
        $app->bootstrap();
        $dbAdapter = $app->getBootstrap()->getResource('db'); /* @var $db Zend_Db_Adapter_Pdo_Mysql */
        $this->dbConnection = new Zend_Test_PHPUnit_Db_Connection($dbAdapter, 'unittests');

        $dbAdapter->exec("CREATE TABLE IF NOT EXISTS `villains` (
              `id` int(11) NOT NULL AUTO_INCREMENT,
              `name` varchar(255) NOT NULL,
              `mode` varchar(255) NOT NULL,
              PRIMARY KEY (`id`)
            ) ENGINE=InnoDB  DEFAULT CHARSET=latin1");

        $dbAdapter->exec('DELETE FROM villains'); // clean out db data

        $dbAdapter->exec("
            INSERT INTO `villains` VALUES(1, 'Joker', 'employer');
            INSERT INTO `villains` VALUES(2, 'Kingpin', '');
            INSERT INTO `villains` VALUES(3, 'Penguin', '');
        ");
    }

    // ensure the above setup is working as expected
    public function assertPreConditions() {
        $this->assertEquals(3, $this->getRowCount('villains')); 
    }

    public function provideTest1()
    {
        return [
            // form data        is valid?       isRequired?
            [['id' => '1'],     false,          false],
            [['id' => '2'],     true,           false],
            [['id' => '3'],     true,           false],
            [['id' => ''],      true,           false],
            [[],                true,           false],
            [['id' => '856'],   false,          false],
            [['id' => '856'],   false,          true],
            [['id' => ''],      false,          true],
            [[],                false,          true],
        ];
    }

    public function provideTest2()
    {
        return [
            //  form data       is valid?       isRequired?
            [['id' => '1'],     true,           false],
            [['id' => '2'],     false,          false],
            [['id' => '3'],     false,          false],
            [['id' => ''],      true,           false],
            [[],                true,           false],
            [['id' => '856'],   false,          false],
            [['id' => '856'],   false,          true],
            [['id' => ''],      false,          true],
            [[],                false,          true],
        ];
    }

    /**
     * @dataProvider provideTest1
     */
    public function test1(array $data, $isValid, $isRequired)
    {
        $form = new Zend_Form();
        $id = new Zend_Form_Element_Select("id");
        $id->setRegisterInArrayValidator(false);
        $id->addValidator(new Zend_Validate_Db_RecordExists(array(
            'table' => 'villains',
            'field' => 'id',
            'exclude' => "mode != 'employer'"
        )));
        $id->setRequired($isRequired);
        $form->addElement($id);

        // produces the query
        // SELECT `villains`.`id`
        // FROM `villains`
        // WHERE (`id` = :value) AND (mode != 'employer')
        // LIMIT 1

        $this->assertSame($isValid, $form->isValid($data));
    }

    /**
     * @dataProvider provideTest2
     */
    public function test2(array $data, $isValid, $isRequired)
    {
        $form = new Zend_Form();
        $id = new Zend_Form_Element_Select("id");
        $id->setRegisterInArrayValidator(false);
        $id->addValidator(new Zend_Validate_Db_RecordExists(array(
            'table' => 'villains',
            'field' => 'id',
            'exclude' => "mode = 'employer'"
        )));
        $id->setRequired($isRequired);
        $form->addElement($id);

        // produces the query
        // SELECT `villains`.`id` 
        // FROM `villains` 
        // WHERE (`id` = :value) AND (mode = 'employer') 
        // LIMIT 1

        $this->assertSame($isValid, $form->isValid($data));
    }
}

关于php - Zend_Validate_Db_RecordExists 排除逻辑问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14706653/

相关文章:

php - 无法 Autowiring PasswordHasherInterface

php - Netbeans:如何配置远程服务器的 PHPUnit 路径?

zend-framework - Zend 仅执行两个表更新之一

zend-framework - Zend_Validate_Db_RecordExists 与 Doctrine 2?

javascript - 在点击事件上使用 Javascript 加载 Textarea

php - 循环遍历 MYSQL 查询的结果并将其插入表中

php - Oracle中 "mysql_real_escape_string"的等效命令是什么?

php - 什么正则表达式模式是正确的只允许双重类型?

zend-framework - 使用 Zend Framework 验证日期是否大于或等于今天的日期验证器

centos - X-debugger 在查看 PHP 服务器端脚本中的变量时显示意外更改