Page 1 of 1

How do I validate user input in the ACP?

Posted: Tue May 16, 2017 5:39 am
by austin881
Can someone point me to some documentation or forum topics on validating input boxes server-side in my extension?

I thought I could just do something like this...

Code: Select all

static public function getSubscribedEvents()
    {
        return [
            'core.validate_config_variable'  => 'validate_config_variable'
        ];
    }

Code: Select all

    public function validate_config_variable($event)
    {
        $input = $event['cfg_array']['s3_aws_access_key_id'];

        // Check if the validate test is for s3.
          if (($event['config_definition']['validate'] == 's3_aws_access_key_id') && ($input !== '')) {
            // Store the error and input event data.
            $error = $event['error'];

            // Add error message if the input is not a valid AWS Access Key Id.
              if (!preg_match('/[A-Z0-9]{20})/', $input)) {
                $error[] = $this->user->lang('ACP_S3_AWS_ACCESS_KEY_ID_INVALID', $input);
              }

            // Update error event data.
            $event['error'] = $error;
          }
    }
What am I missing? Upon clicking Submit button the success page is displayed, the validation doesn't seem to run at all. I put debug prints error_log() and die() in the validate_config_variable() function and they are never called/printed.
687474703a2f2f6936332e74696e797069632e636f6d2f3135637a7470342e6a7067.png
If you'd like to see the rest of the code, it is located here: https://github.com/AustinMaddox/phpbb-extension-s3

Re: How do I validate user input in the ACP?

Posted: Tue May 16, 2017 8:28 am
by RMcGirr83
You can't use that within an acp module file. You have to do it within the actual file prior to the submit so something link this.

Code: Select all

        add_form_key('AustinMaddox/s3');
		if (!preg_match('/[A-Z0-9]{20})/', $input)) {
			$error[] = $this->user->lang('ACP_S3_AWS_ACCESS_KEY_ID_INVALID', $input);
		}
        if ($request->is_set_post('submit') && ! sizeof($error))
that event is only for validating entries that have been added to the defautl acp modules.

Re: How do I validate user input in the ACP?

Posted: Tue May 16, 2017 1:31 pm
by austin881
Thanks Rich. You said...
You can't use that within an acp module file.
I didn't think I was. I was using it in an event listener.
You have to do it within the actual file prior to the submit so something link this.
Do it within what file?
that event is only for validating entries that have been added to the defautl acp modules
That makes sense. I used the Google Analytics module as inspiration which puts a field in the Board settings page of the ACP. So if I can't use the core.validate_config_variable event, what can I use and which file does it go in? Does that code you suggested go in extname/acp/main_module.php?

Re: How do I validate user input in the ACP?

Posted: Tue May 16, 2017 2:10 pm
by RMcGirr83
austin881 wrote:
Tue May 16, 2017 1:31 pm
Thanks Rich. You said...
You can't use that within an acp module file.
I didn't think I was. I was using it in an event listener.
But you aren't using event listeners for your acp stuffs...you are using an acp module. That's the difference.
Does that code you suggested go in extname/acp/main_module.php?
:+1:

Re: How do I validate user input in the ACP?

Posted: Tue May 16, 2017 2:23 pm
by austin881
Ok that helps. Now we're getting somewhere! :mrgreen:

I've put this code in ext/AustinMaddox/s3/acp/main_module.php

Code: Select all

if (!preg_match('/[A-Z0-9]{20}/', $request->variable('s3_aws_access_key_id', ''))) {
    trigger_error($user->lang('ACP_S3_AWS_ACCESS_KEY_ID_INVALID', $request->variable('s3_aws_access_key_id', '')) . adm_back_link($this->u_action));
}

if (!preg_match('/[A-Za-z0-9/+=]{40}/', $request->variable('s3_aws_secret_access_key', ''))) {
    trigger_error($user->lang('ACP_S3_AWS_SECRET_ACCESS_KEY_INVALID', $request->variable('s3_aws_secret_access_key', '')) . adm_back_link($this->u_action));
}
Screen Shot 2017-05-16 at 8.22.16 AM.png
Thanks again Rich!

Re: How do I validate user input in the ACP?

Posted: Tue May 16, 2017 3:29 pm
by RMcGirr83
A green error?

Code: Select all

trigger_error($user->lang('ACP_S3_AWS_SECRET_ACCESS_KEY_INVALID', $request->variable('s3_aws_secret_access_key', '')) . adm_back_link($this->u_action), E_USER_WARNING);
;)

Re: How do I validate user input in the ACP?

Posted: Wed May 17, 2017 4:03 am
by 3Di
On a side note, you should code an array() of errors, so to provide the exact error to the end user.

The error message(s) should be "user-friendly", the average Jon Doe admin doesn't have a clue what is a regular expression. :)

Re: How do I validate user input in the ACP?

Posted: Wed May 17, 2017 2:09 pm
by austin881
Good advice! You mean so they can see all errors? Something like this...

Code: Select all

$errors = [];
if (!preg_match('/[A-Z0-9]{20}/', $request->variable('s3_aws_access_key_id', ''))) {
    $errors[] = $user->lang('ACP_S3_AWS_ACCESS_KEY_ID_INVALID', $request->variable('s3_aws_access_key_id', ''));
}

if (!preg_match('/[A-Za-z0-9\/+=]{40}/', $request->variable('s3_aws_secret_access_key', ''))) {
    $errors[] = $user->lang('ACP_S3_AWS_SECRET_ACCESS_KEY_INVALID', $request->variable('s3_aws_secret_access_key', ''));
}

if ($errors) {
    trigger_error(implode('<br><br>', $errors) . adm_back_link($this->u_action), E_USER_WARNING);
}
Screen Shot 2017-05-17 at 8.03.14 AM.png

Re: How do I validate user input in the ACP?

Posted: Thu May 18, 2017 2:08 am
by 3Di
You got it, the idea. Something like this, not tested and written on the fly..

Your acp module

Code: Select all

class my_ext_acp_module
{
	var $u_action;

	// .....

	function main($id, $mode)
	{
		$this->tpl_name = 'acp_template.html';

		// ......
		//......

		$errors = [];
		if (!preg_match('/[A-Z0-9]{20}/', $request->variable('s3_aws_access_key_id', '')))
		{
			$errors[] = $user->lang('ACP_S3_AWS_ACCESS_KEY_ID_INVALID';
		}
		if (!preg_match('/[A-Za-z0-9\/+=]{40}/', $request->variable('s3_aws_secret_access_key', '')))
		{
			$errors[] = $user->lang('ACP_S3_AWS_SECRET_ACCESS_KEY_INVALID';
		}

		// .....

		$template->assign_vars(array(
			'S_ERRORS'		=> (sizeof($errors)) ? true : false,
			'ERRORS_MSG'		=> implode('<br />', $errors),
			'U_ACTION'		=> $this->u_action
			)
		);
	}
}
in your /adm/style/acp_template.html file

right before..

Code: Select all

<form id="main" method="post" action="{U_ACTION}// ... etc..
add this snippet

Code: Select all

<!-- IF S_ERRORS -->
	<div class="errorbox">
		<h3>{L_WARNING}</h3>
		<p>{ERRORS_MSG}</p>
	</div>
<!-- ENDIF -->
If you are using 3.2.x only, simply replace the $user objet with the $language one (for langs), your choice.

The *_CPs are decoupled from the framework, still. Old coding method rules, so to speak.

Re: How do I validate user input in the ACP?

Posted: Thu May 18, 2017 2:19 am
by austin881
So I'm just curious... Why is your method preferred over what I did? Don't they both achieve the same result?

Also, sorry but I didn't understand your last two sentences at all.

Re: How do I validate user input in the ACP?

Posted: Thu May 18, 2017 2:34 am
by 3Di
austin881 wrote:
Thu May 18, 2017 2:19 am
Why is your method preferred over what I did? Don't they both achieve the same result?
Because of code consistency, and because the template stuff uses CSS classes as well.
Let's say also, some styles writer coded a different CSS rule for the class "errorbox"?
austin881 wrote:
Thu May 18, 2017 2:19 am
I didn't understand your last two sentences at all.
About the User obj against the Language one?
phpBB 3.2 introduced the language obj, you can use
$language->lang.... (only for 3.2)
instead of
$user->lang,,, (3.1 and 3.2)

For the latter, I mean all of the *_CPs (ACP, MCP. UCP) need a re-factoring, use the methods used for 3.0.x more or less. More about that on area51.

Oh, forgot to add, before of your checks in PHP you should check also for this..

Code: Select all

// ......
		if (sizeof($errors))
		{
			$submit = false;
		}
//......
Edit: this method also (if I am not mistaken) will keep the admin on the same page but with the error message(s) on top of it. Yours, instead, tosses the error message(s) like a die(); , the admin needs to click on the link to get back to that page, which is not so elegant IMO. :). A Latinism, appropriated, could be "Coitus interruptus". ;)

Re: How do I validate user input in the ACP?

Posted: Thu May 18, 2017 4:47 am
by austin881
$submit = false; ??????????
What would that do? That variable doesn't even exist.

Re: How do I validate user input in the ACP?

Posted: Thu May 18, 2017 5:07 am
by 3Di
Man, I told you I am writing on the fly? :roll:

Code: Select all

$submit = $request->is_set_post('submit');

if (sizeof($errors))
{
	$submit = false;
}
or..

Code: Select all

if ($request->is_set_post('submit') && !sizeof($errors))
{
// do your magic..
}
Have a look at some validated extensions and read as much as you can, Docs and everything.

Re: How do I validate user input in the ACP?

Posted: Thu May 18, 2017 6:03 am
by 3Di
I spent some minute after your github. I meant some thing like this, adjust the template accordingly, NOT tested, on the fly.

Code: Select all

namespace AustinMaddox\s3\acp;

class main_module
{
var $u_action;

function main($id, $mode)
{
	global $config, $request, $template, $user;

	$user->add_lang('acp/common');

	$this->tpl_name = 's3_body';
	$this->page_title = $user->lang('ACP_S3_TITLE');

	add_form_key('AustinMaddox/s3');

	if ($request->is_set_post('submit'))
	{
		if (!check_form_key('AustinMaddox/s3'))
		{
			trigger_error('FORM_INVALID');
		}

		$errors = [];

		if (!preg_match('/[A-Z0-9]{20}/', $request->variable('s3_aws_access_key_id', '')))
		{
			$errors[] = $user->lang('ACP_S3_AWS_ACCESS_KEY_ID_INVALID');
		}
		if (!preg_match('/[A-Za-z0-9\/+=]{40}/', $request->variable('s3_aws_secret_access_key', '')))
		{
			$errors[] = $user->lang('ACP_S3_AWS_SECRET_ACCESS_KEY_INVALID');
		}

		if (!sizeof($errors))
		{
			$config->set('s3_aws_access_key_id', $request->variable('s3_aws_access_key_id', ''));
			$config->set('s3_aws_secret_access_key', $request->variable('s3_aws_secret_access_key', ''));
			$config->set('s3_region', $request->variable('s3_region', ''));
			$config->set('s3_bucket', $request->variable('s3_bucket', ''));

			trigger_error($user->lang('ACP_S3_SETTING_SAVED') . adm_back_link($this->u_action));
		}
	}

	$template->assign_vars([
		'S_ERRORS'			=> (sizeof($errors)) ? true : false,
		'ERRORS_MSG'			=> implode('<br />', $errors),
		'U_ACTION'			=> $this->u_action,
		'S3_AWS_ACCESS_KEY_ID'		=> $config['s3_aws_access_key_id'],
		'S3_AWS_SECRET_ACCESS_KEY'	=> $config['s3_aws_secret_access_key'],
		'S3_REGION'			=> $config['s3_region'],
		'S3_BUCKET'			=> $config['s3_bucket'],
		]);
	}
}