April 5, 2016

MVC Design – views with content for a usergroup

H0mebrewer’s Question:

I’m writing my first MVC application in PHP. I don’t want to use any framework.

Now I’m searching for a good solution or best practise to display elements for users in views, only if they are allowed to interact with the function that a specific element calls.

The app loads a template file in the view.
Within the template file I show the data from the model, which is passed from the controller to the view.

From controller

public function showUserList() {
    $userList = $this->model->getUserList();
    $this->view->loadTemplate($userList, 'user_list.php');
}

From view:

class user_view  {
    public function loadTemplate($data, $file, $buffer= false){
        if($buffer === true){
            ob_start();
            include dirname(__FILE__).'/templates/'.$file;
            $c = ob_get_contents();
            ob_end_clean();
            return $c;
        }else{
            include dirname(__FILE__).'/templates/'.$file;
        }
    }
}

Template:

<table class="table" id="data-table">
    <thead>
        <tr>
        <th>Name</th>
        <th>Username</th>
        <th>E-Mail</th>
        <th>Group</th>
        <th>Action</th>
        </tr>
    </thead>
    <tbody>
    <?php
       if(is_array($data)){

          foreach($data as $key => $value){
          ?>
            <tr>
                <td><?php echo $data['name'].' '.$data['surname']; ?></td>
                    <td><?php echo $data['abbr']; ?></td>
                    <td><?php echo $data['email']; ?></td>
                    <td><?php echo $data['gr_name']; ?></td>
                    <td>

                    <div data-access="," onclick="$user_controller.showUserChangeView('<?php echo $data['id']; ?>')" class="btn btn-primary">edit</div>
                    <div data-access="checkAccess" onclick="$user_controller.deleteUser('<?php echo $data['id']; ?>')" class="btn btn-danger">delete</div>

                    </td>
                </tr>

          <?php
          }

       }
    ?>
    </tbody>
</table>
</div>

I want to display buttons or menuitmes only, if a user is permitted to call the function of the button or the menuitem.

My first approach ist to create a template file with all elements which could be displayed. Elements which should not be accessible for all users get an data attribute.

The view loads the template, a DOM parser pareses the file, checks if the user is permitted to call that function with a data attribute.
If the user is not permitted to call that function, the element will be removed.
This is not yet implemented because I’m not sure if this is that a good solution or how I can do it even better?

My suggestion is to implement either ACL (Access Control List) or RBAC (Role Based Access Control) depending on what you find useful. I prefer RBAC so I will give a minimalistic example of one.

Create a list of all possible actions a user can make and define roles which might have acess to them.

// List of permissions (the actual term to define resources in RBAC) for the users
$actions = array(
    'view' => array(ROLE_USER, ROLE_OWNER, ROLE_MANAGER, ROLE_ADMIN),
    'edit' => array(ROLE_OWNER, ROLE_ADMIN),
    'delete' => array(ROLE_OWNER, ROLE_ADMIN),
    'change_pass' => array(ROLE_OWNER, ROLE_MANAGER, ROLE_ADMIN)
)

Now when you display the button for these actions, you can check if current user has any of the role which allows him to access the actions. If answer to that is “yes” then show them otherwise don’t show them at all.

$currentUserRole = '..'; //Retrieve however you want
foreach($actions as $allowed_roles) {
    if(in_array($currentUserRole, $allowed_roels)) {
        echo "<div ...>"; // Basically show the action
    }
    // If not carry on to next action with out showing
}

(Note: Not showing only might not be enough for it be secured, so we must also the check then when executing the action as well)

Update: You would the put the above code in the following part:

<table class="table" id="data-table">
    <thead>
        <tr>
        <th>Name</th>
        <th>Username</th>
        <th>E-Mail</th>
        <th>Group</th>
        <th>Action</th>
        </tr>
    </thead>
    <tbody>
    <?php
       if(is_array($data)){

          foreach($data as $key => $value){
          ?>
            <tr>
                <td><?php echo $data['name'].' '.$data['surname']; ?></td>
                    <td><?php echo $data['abbr']; ?></td>
                    <td><?php echo $data['email']; ?></td>
                    <td><?php echo $data['gr_name']; ?></td>
                    <td>
                        $currentUserRole = '..'; //Retrieve however you want
                        foreach($actions as $allowed_roles) {
                            if(in_array($currentUserRole, $allowed_roels)) {
                               echo "<div ...>"; // Basically show the action
                            }
                            // If not carry on to next action with out showing
                        }
                    </td>
                </tr>

          <?php
          }

       }
    ?>
    </tbody>
</table>
</div>
May 7, 2013

PHP – Avoid reloading page after form submit

User2108393’s Questions:

I’m new to php and web-programming… I’m working on a school project modifying databases through a corporate site.

I’m using some forms to allow the user to look for information that will be used to fill up other forms on the same page. In this case, a car rental, I look for available cars, show them on a table and then the user picks a car and its info would fill up some other inputs on the same page.

I’m able to do the search and show the result, but then when the user picks the car and clicks submit the whole page is uploaded again. Please, any suggestions?

J.

Redirect to a different page/route, other than the one page was submitted to.

An example for different page redirection.

header("location: differentpage.php");
exit;

Once you are in differentpage.php you cannot reload the POST request. TO get the data you can use SESSION or GET parameter as per requirements.

September 21, 2012

PHP backend / frontend security

Question by William Yang

Hello all,

While taking my time in the bath I though of something interesting. In PHP, how do you tell if the users’ forms submitted is valid and not fraud (i.e. some other form on some other site with action=”http://mysite.com/sendData.php”)? Because really, anyone can create a form that will try send and match $_POST variables in the real backend. How can I make sure that that script is legit (from my site and only my site) so I don’t have some sort of cloning-site data-steal thing going on?

I have some ideas but not sure where to start

  • Generate a one-time key and store in hidden input field
  • Attempt (however possible) to grab the url on which the form is located (probably not possible)
  • Using some really complicated PHP goodies to determine where the data is sent (possible)

Any ideas? Thanks all!

Answer by Nathan Sire

Most of these attempts from hackers will be used by curl. It’s easy to change the referring agent with curl. You can even set cookies with curl. But spoofing md5 hashed keys with a private salt and storing it in session data will stop most average hackers and bots. Keeping the keys stored in a database will add authentication.

Answer by Starx

There are few simple ways like:

  • Checking $_SERVER['HTTP_REFERER'] to ensure your host was the referring script
  • Adding hashing keys in the forms and checking them with the server session variable stored.

But all the above can be manipulated and spoofed in some way. So, you can use CSRF Validations. Here is a very good article on this.

Other additional techniques I have encountered are:

  • Adding time limits to forms and ensure they are submitted with in that time.
  • On every interaction with the form, send AJAX request to validate and reactive the form’s timelimit.
March 14, 2012

displaying pdf files stored in myql database PHP

Question by Samer El Gendy

i am trying to display pdf files stored in mysql database in the browser when the user request to.

structure of the mysql table: 
CREATE TABLE `file` (
`id` Int Unsigned Not Null Auto_Increment,
`name` VarChar(255) Not Null Default 'Untitled.txt',
`mime` VarChar(50) Not Null Default 'text/plain',
`size` BigInt Unsigned Not Null Default 0,
`data` MediumBlob Not Null,
`created` DateTime Not Null,
PRIMARY KEY (`id`)
)
php code: 
$query = "
            SELECT `type`, `name`, `size`, `data`, `mime`
            FROM `file`
            WHERE `id` = {$id}";
        $result = $dbLink->query($query);
        if($result) {
            // Make sure the result is valid
            if($result->num_rows == 1) {
            // Get the row
                $row = mysqli_fetch_assoc($result);
                // Print headers
                header('Accept-Ranges: bytes');
                header('Content-Transfer-Encoding: binary');
                header("Content-Type: ".$row['mime']);
                header("Content-Length: ".$row['size']);
                header("Content-Disposition: inline; filename=".$row['name']);
                echo $row['data'];
            }
        }
code to save file to database:
if(isset($_FILES['uploaded_file'])) {
    // Make sure the file was sent without errors
    if($_FILES['uploaded_file']['error'] == 0) {
        // Connect to the database
        $dbLink = new mysqli('localhost', 'REDACTED',"REDACTED", 'pdfs');
        if(mysqli_connect_errno()) {
            die("MySQL connection failed: ".mysqli_connect_error());
        }

        // get all required data
        $name = $dbLink->real_escape_string($_FILES['uploaded_file']['name']);
        $type = $dbLink->real_escape_string($_FILES['uploaded_file']['type']);
        $data = $dbLink->real_escape_string(file_get_contents($_FILES  ['uploaded_file']['name']));
        $size = intval($_FILES['uploaded_file']['size']);

        // Create the SQL query
        $query = "
            INSERT INTO `file` (
                `name`, `type`, `size`, `data`, `created`
            )
            VALUES (
                '{$name}', '{$type}', {$size}, '{$data}', NOW()
            )";

        // Execute the query
        $result = $dbLink->query($query);

        // Check if it was successfull
        if($result) {
            echo 'Success! Your file was successfully added!';
        }
        else {
            echo 'Error! Failed to insert the file'
               . "<pre>{$dbLink->error}</pre>";
        }

however, when i try to view a pdf, adobe reader start loading and then i get this error massage: the file is damaged and could not be repaired.
am i doing something wrong?

Answer by Starx

Frankly, I don’t like this way at all.

KISS

Keep it Short & Simple

Whatever you are trying to do, there is better way of doing it.

  1. If security is the problem you have .htaccess and access roles
  2. If file handling is the problem you have PHP.
  3. If protected download is a problem then again with the combination of PHP and its session handling, you can do it.
  4. If viewing is the problem you have browser that.
  5. If you want to force download the file, then PHP’s header tags is enough.
...

Please fill the form - I will response as fast as I can!