CodeIgniter Forums
Form Generation Library - Printable Version

+- CodeIgniter Forums (https://forum.codeigniter.com)
+-- Forum: Archived Discussions (https://forum.codeigniter.com/forumdisplay.php?fid=20)
+--- Forum: Archived Libraries & Helpers (https://forum.codeigniter.com/forumdisplay.php?fid=22)
+--- Thread: Form Generation Library (/showthread.php?tid=16439)



Form Generation Library - El Forum - 11-22-2009

[eluser]hugle[/eluser]
[quote author="macigniter" date="1258944312"][quote author="hugle" date="1258466711"]Hello everyone again,

I have found a little bug in Form library, I think, I'll explain:
I have simple form:
Code:
print_r($_POST);
    
        $this->form->open('/welcome/test')
        ->fieldset('Enter keywords to search for')
        ->text('search', 'Keywords:', '')->indent(150)
        ->submit('Submit')
        ->validate();
        
        if ($this->form->valid)
        {
            $post_data= array();
            $post_data = $this->form->get_post();
            print_r($post_data);
        }
And if I enter '&DEV;_0887&' as a search value(without quotes), and press submit, I get malicious data:
&DEV;_0887& becomes &DEV;_0887&

As you can see I'm not using any rules, but If I try to access $_POST before `if ($this->form->valid)` I have correct value = &DEV;_0887&.
Even $_POST inside if ($this->form->valid) has malicous data = &DEV;_0887&

I could not reproduce the bug... maybe some of you came to this problem?

Thank you![/quote]

I don't see a difference between &DEV;_0887& and &DEV;_0887&
Am I missing something!?!?[/quote]

Hello
seems this this forum is also replacing some of these chars (strange?! maybe they are using your lib too?Smile)) ).
I tried native Form_validation and your Form_Generation_Library
CI validation - works correctly,
and your Library is corrupting data a bit..

as an example:
type into <input>:
& D E V _ 0 8 8 7 &
(without spaces)
and you will get:
&DEV;_0887&

Hope this can be fixed easilySmile)))
thank you for such a wonderful LIB!Smile


Form Generation Library - El Forum - 11-23-2009

[eluser]macigniter[/eluser]
[quote author="hugle" date="1258957903"]
strange?! maybe they are using your lib too?Smile))
[/quote]

haha. i doubt it Wink

[quote author="hugle" date="1258957903"]
type into <input>:
& D E V _ 0 8 8 7 &
(without spaces)
and you will get:
&DEV;_0887&
[/quote]

I tried this. But couldn't reproduce your problem. The output is correct in my local test environment... I have no idea where the ";" would come from...?


Form Generation Library - El Forum - 11-23-2009

[eluser]hugle[/eluser]
Hm... it's really strange, I've just downloaded your full package to test things once again...
What I did is:
replaced from your welcome controlled ->onsuccess() with:
Code:
->validate();
if($this->form->valid)
{
   $post_data= array();
   $post_data = $this->form->get_post();
            
   print_r($post_data);
}
if you have a bit of time, please go to: http://beta.invista.lt/index.php/welcome
after submitting data, you'll see the result in the top of document.
the data is corruptedSad I don't understand why only I am getting such problems, could it be PHP.ini setup ..?
rrrrrr!Smile))


other things, not so important maybe.. but?

take a lookSmile
Code:
->select('multiple', $multiple, 'Select multiple', '2, 4', '', 'style=width:150px')

this displays nice form, but if I want none selected, and replace
'2, 3' with '', the html output looks not the way it should be, so I'm now setting:
Code:
->select('multiple', $multiple, 'Select multiple', '0, 0', '', 'style=width:150px')
if I want none selected.
I can live with thatSmile))

and I think.. the last thing would be with textareas:
If I add disabled, like this:
Code:
->textarea('notes', 'Notes', 'trim', "This textarea has some default text.\n\nAwesome!", 'disabled="disabled"')
the text in the textarea disappears after submitting data:
as an example you can go to:
http://beta.invista.lt/index.php/welcome
and press SUBMIT not entering any dataSmile

Hope that helps Smile sorry for bugging you so muchSmile))

good luck mateSmile))
If you want you can catch me on skype: huglee
ANd I could do more tests for you Smile

Thanks and waiting for your replySmile))


Form Generation Library - El Forum - 11-23-2009

[eluser]macigniter[/eluser]
[quote author="hugle" date="1259012320"]
"&DEV;_0887&" issue
[/quote]

This was related to

Code:
$this->input->post($var, TRUE);

in the get_post() method. It's fixed now...

[quote author="hugle" date="1259012320"]
take a lookSmile
Code:
->select('multiple', $multiple, 'Select multiple', '2, 4', '', 'style=width:150px')

this displays nice form, but if I want none selected, and replace
'2, 3' with '', the html output looks not the way it should be, so I'm now setting:
Code:
->select('multiple', $multiple, 'Select multiple', '0, 0', '', 'style=width:150px')
if I want none selected.
I can live with thatSmile))
[/quote]

If you don't have multiple selected standard values the form generation library doesn't know that the select is a multiple select. So you have to tell it by adding multiple=true or multiple=multiple:

Code:
->select('multiple', $multiple, 'Select multiple', '', '', 'style=width:150px,multiple=true')

[quote author="hugle" date="1259012320"]
If I add disabled, like this:
Code:
->textarea('notes', 'Notes', 'trim', "This textarea has some default text.\n\nAwesome!", 'disabled="disabled"')
the text in the textarea disappears after submitting data:
as an example you can go to:
http://beta.invista.lt/index.php/welcome
and press SUBMIT not entering any dataSmile
[/quote]

I've had that problem before... Instead of disabled you should use readonly. That should do the trick!


Form Generation Library - El Forum - 11-23-2009

[eluser]hugle[/eluser]
Thanks for the ideaSmile))


Form Generation Library - El Forum - 11-24-2009

[eluser]dinhtrung[/eluser]
Quote:[quote author="dinhtrung" date="1258841860"]
Also, when I use button() instead of submit(), I can't submit my form. I couldn't understand why. Although output_profiler show that there are POST variables, but the form didn't call the model method. I prefer button with type='submit' rather than just input type='submit' for more theme attributes.

This should work... did you find the solution?[/quote]
Yep, I didn't give the name and value for the submit button, so _check_posted is not work correctly.
Usually, I didn't provide controller name for Submit or Button elements, because it can break my Models.
Here is the patch for Form Generation to support prefix and suffix for elements, and generate CAPCHA from CI Captcha plugins, not from reCaptcha.


Form Generation Library - El Forum - 11-24-2009

[eluser]macigniter[/eluser]
[quote author="dinhtrung" date="1259077167"]
Here is the patch for Form Generation to support prefix and suffix for elements, and generate CAPCHA from CI Captcha plugins, not from reCaptcha.[/quote]

Cool! Thanks, I'll check it out!


Form Generation Library - El Forum - 11-24-2009

[eluser]dinhtrung[/eluser]
Thank a bunch! I found Form Generation very useful, especially when use with models to validate and process user inputs.
Here is MY_Model for Form Generation.
Code:
<?php     if (!defined('BASEPATH')) exit('No direct script access allowed');

class MY_Model extends Model
{
    public $table = "";
    public $sort = "";
    public $pkey = "";
    
    /* Common messages for notification. */
    public $quiet = FALSE;

    public $update_ok = "Đã cập nhật dữ liệu trong bảng ";
    public $update_fail = "Không thể cập nhật dữ liệu trong bảng ";

    public $delete_ok = "Đã xóa dữ liệu trong bảng ";
    public $delete_fail = "Không thể xóa dữ liệu trong bảng ";

    public $create_ok = "Đã thêm dữ liệu vào trong bảng ";
    public $create_fail = "Không thể thêm dữ liệu mới vào trong bảng ";

    function __construct()
    {
        parent::__construct();
    }
    
    function get($where = FALSE)
    {
        if ($this->table)
        {
            if (is_array($where)) $this->db->where($where);
            elseif ($this->pkey && is_string($where)) $this->db->where($this->pkey, $where);
            if ($this->sort) $this->db->orderby($this->sort);
            $r = $this->db->get($this->table);
            if ($r->num_rows()) return $r->result_array();
            else return FALSE;
        } else show_error("Table name is undefined.");
    }
    
    function create(&$form, $data = FALSE)
    {
        if ($this->table)
        {
            $data = $this->retrieve($data);
            if (! count($data) && ! $this->quiet) $this->session->set_flashdata('notice', $this->create_fail);
            else {
                $this->db->insert($this->table, $data);
                if (! $this->quiet) $this->session->set_flashdata('success', $this->create_ok);
                return $this->db->insert_id();
            }
        } else show_error("Table name is undefined.");
    }
    function update(&$form, $data = FALSE)
    {
        if ($this->table)
        {
            if ($this->pkey)
            {
                if (! array_key_exists('uniqueid', $data) && ! $this->quiet) $this->session->set_flashdata('notice', $this->update_fail);
                else $pkey = $data['uniqueid'];
                if (($pkey == "") && ! $this->quiet) $this->session->set_flashdata('notice', $this->update_fail);
                else {
                    $data = $this->retrieve($data);                
                    $this->db->where($this->pkey, $pkey);                
                    $this->db->update($this->table, $data);
                    if (! $this->quiet) $this->session->set_flashdata('success', $this->update_ok);
                }
            } else show_error("Table primary key is undefined.");
        } else show_error("Table name is undefined.");
    }
    
    function delete($pkey)
    {
        if ($this->table)
        {
            if ($this->pkey)
            {
                if (! $pkey && ! $this->quiet) $this->session->set_flashdata('success', $this->delete_fail);
                else {
                    $this->db->where($this->pkey, $pkey);
                    $this->db->delete($this->table);
                    $this->session->set_flashdata('success', $this->delete_ok);
                }
            } else show_error("Table primary key is undefined.");
        } else show_error("Table name is undefined.");
    }
    # Retrieve data from input->post(). Only scan for table's fields.
    function retrieve($datatmp = FALSE)
    {
        if ($this->table)
        {
            $fields = $this->db->list_fields($this->table);
            $data = array();
            if (! $datatmp)
                foreach ($fields as $field)
                {
                   if ($this->input->post($field) != "") $data[$field] = $this->input->post($field, TRUE);
                }
            else
                foreach ($fields as $field)
                {
                   if (array_key_exists($field, $datatmp) && ($datatmp[$field] != "")) $data[$field] = $datatmp[$field];
                }            
            return $data;
        } else show_error("Table name is undefined.");        
    }
    # Fill in default values for Form.
    function init($datatmp = FALSE)
    {
        if ($this->table)
        {
            $fields = $this->db->list_fields($this->table);
            if (! $datatmp){
                foreach ($fields as $field)
                {
                   $data[$field] = "";
                }
                if (count($this->_default)) $data = array_merge($data, $this->_default);
            } else {
                foreach ($fields as $field)
                {
                   if (array_key_exists($field, $datatmp) && ($datatmp[$field] != "")) $data[$field] = $datatmp[$field];
                   else $data[$field] = "";
                }
                if (count($this->_default)) $data = array_merge($this->_default, $data);
            }
            return $data;
        } else show_error("Table name is undefined.");
    }
}

/* End of file application/models/BaseModel.php */
/* Author : Nguyen Dinh Trung <[email protected]> */



Form Generation Library - El Forum - 11-24-2009

[eluser]dinhtrung[/eluser]
Strip out unneccessary inputs, like 'submit' fields. Also, only update and insert into table if user post value. I extends this Model for every table in the database, with custom message. Example:
Code:
&lt;?php  if (!defined('BASEPATH')) exit('No direct script access allowed');
    class Role_m extends MY_Model
{
    function __construct()
    {
        parent::__construct();
        $this->table = "roles";
        $this->pkey = "id";
        $this->sort = "name";
                $this->update_ok = "Succesfully update data in table roles";
    }
    # Extends the retrieve function in parent class, for input post process.
        # For e.g, the "permissions" fields is encrypted for security.
    function retrieve($data = FALSE)
    {
        $data = parent::retrieve($data);
        $this->load->library('encrypt');
        $data["permissions"] = $this->encrypt->encode(str_replace("\n", ';',  $data["permissions"]));
        return $data;
    }
}

/* End of file : modules/users/models/role_m.php */
In my Controller:
Code:
&lt;?php if (!defined('BASEPATH')) exit('No direct script access allowed');



class Roles extends Backend

{

    function __construct()

    {

        parent::__construct();

        $this->load->model('role_m');

    }



    function index()

    {
        $this->table->set_heading('ID', 'Name', 'Description', 'Permissions');
        $qry = $this->db->orderby('name')->get('roles');
        $this->table->set_caption("Site Roles");
        $this->main = $this->table->generate($qry);
        $this->_render();

    }



    function create()

    {

        $this->load->library('form');
        $this->form->open($this->uri->uri_string())                
                ->fieldset("Role Settings")
                ->text('name', 'Role name', 'max_length[20]|required|trim')
                ->text('description', 'Description', 'max_length[100]')
                ->textarea('permissions', 'Permissions')
                ->button('<span class="ss_sprite ss_accept">OK</span>', 'submit', 'submit', 'value="submit"')
                ->button('<span class="ss_sprite ss_cancel">Reset</span>', '', 'reset', '')
                ->model('role_m', 'create')
                ->onsuccess('redirect', $this->uri->uri_string());
        $this->main = $this->form->get();
        $this->main = $this->form->errors.$this->main;
        $this->_render();

    }
    
    function update()
    {
        $pkey = $this->uri->segment(4);
        $def = $this->db->where('id', $pkey)
                                ->get('roles')
                                ->row_array();        
        $this->load->library('form');
        $this->form->open($this->uri->uri_string())                
                ->fieldset("Role Settings")
                ->hidden('uniqueid', $this->uri->segment(4))
                ->text('name', 'Role name', 'max_length[20]|required|trim')
                ->text('description', 'Description', 'max_length[100]')
                ->textarea('permissions', 'Permissions')
                ->button('<span class="ss_sprite ss_accept">OK</span>', 'submit', 'submit', 'value="submit"')
                ->button('<span class="ss_sprite ss_cancel">Reset</span>', '', 'reset', '')
                ->populate($def)
                ->model('role_m', 'update')
                ->onsuccess('redirect', 'user/roles');
        $this->main = $this->form->get();
        $this->main = $this->form->errors.$this->main;
        $this->_render();
    }
}
Very convenient!


Form Generation Library - El Forum - 11-24-2009

[eluser]dinhtrung[/eluser]
Why didn't hidden fields be filled after validation? I changed.
I didn't understand much about set_value() function in PHP5, although read the manual. For textbox or texarea, you use $this->element->value but for hidden, only set_value($name). Please explain for me. Thanks in advance.
Another idea is to use validate() for populate the rules. For e.g, in PyroCMS, I saw something like:
Code:
$this->rules = array('name' => 'required|trim|max_length[30]', 'password' => 'required|trim');
...
$this->Form_validation->set_rules($rules)
So I modified Form.php like this:
Code:
=== modified file 'libraries/Form.php'
--- libraries/Form.php    2009-11-23 04:55:48 +0000
+++ libraries/Form.php    2009-11-24 17:53:06 +0000
@@ -1490,7 +1490,7 @@
      *
      * Validates the form
      */
-    function validate()
+    function validate($rules = FALSE)
     {    
         $this->_check_post();
        
@@ -1508,7 +1508,11 @@

                     $label = ( ! empty($this->$element->label)) ? $this->$element->label : ucfirst($element);
                    
-                    if ( ! empty($this->$element->rules))
+                    if (is_array($rules))
+                    {
+                        if (array_key_exists($name, $rules)) $this->CI->form_validation->set_rules($name, $label, $rules[$name]);
+                    }
+                    elseif ( ! empty($this->$element->rules))
                     {
                         if ( ! empty($this->$element->group_label)) $label = $this->$element->group_label;
                         if ( ! empty($this->$element->err_label)) $label = $this->$element->err_label;
@@ -1554,7 +1558,8 @@
                             break;
                            
                             case 'hidden':
-                            $this->$element->value = set_value($name);
+                            #$this->$element->value = set_value($name);
+                            $this->$element->atts['value'] = $this->$element->value;
                             break;
                            
                             default:
@@ -2690,7 +2695,7 @@
Then in controllers, I set a private class variable $rules and used in update and insert methods.
Code:
function __construct(){
$this->rules = array('name' => 'max_length[20]|required|trim', 'description' => 'max_length[100]');
}

function update(){
$this->form->open($this->uri->uri_string())                
                ->fieldset("Role Settings")
                ->hidden('uniqueid', $primary_key)
                ->text('name', 'Role name')
                ->text('description', 'Description')
                ->textarea('permissions', 'Permissions')
                ->button('<span class="ss_sprite ss_accept">OK</span>', 'submit', 'submit', 'value="submit"')
                ->button('<span class="ss_sprite ss_cancel">Reset</span>', '', 'reset', '')
                ->populate($def)
                ->validate($this->rules)
                ->model('role_m', 'update')
                ->onsuccess('redirect', 'user/roles');
}