June 8, 2016

How to restrict modification to selected properties of an entity while persisting?

Let’s suppose we have an entity class and a generic FormType corresponding to the entity

class Entry {
    protected $start_time;
    protected $end_time;
    protected $confirmed; // Boolean

    // ... Other fields and getters and setters
}

On the CRUD of this entity, you might not want to allow any modification on start_time or end_time if the entity has been confirmed or in the above case when $confirmed === true

Here are couple of ways this can be solved:

  1. Using the EntityManager you can retrieve original data of the entity. $em->getUnitOfWork()->getOriginalEntityData($entity) returns an array with old data of an entity which can be used to reset the data.

    if($form->isSubmitted() && $editForm->isValid()) {
        // The form was submitted
        if($confirmed === true) { // if the entity was confirmed previously
            $oldData = $em->getUnitOfWork()->getOriginalEntityData($entity);
            $entity->setStartTime($oldData['start_time']);
            $entity->setEndTime($oldData['end_time']);
        }
        // After this you can happily persist the data
        $em->persist($entity);
        $em->flush();
    }
    
  2. Using Form Events

    The following is a Symfony 3 Solution, try this solution for Symfony 2.

    class EntityType extends AbstractType
    {
        public function buildForm(FormBuilderInterface $builder, array $options)
        {
            // ....
            // ....
            // Your form fields
    
            $builder->addEventListener(FormEvents::POST_SET_DATA, array($this, 'onPreSetData'));
        }
    
    
        public function onPreSetData(FormEvent $event) {
            /** @var YourEntity $entity */
            $entity = $event->getData();
            $form = $event->getForm();
    
            if($entity instanceof YourEntity) {
                if ($entity->getTimesheetEntry()->getTimeApproved() === true) {
                    $config = $form->get('start_time')->getConfig();
                    $options = $config->getOptions();
                    $options['disabled'] = true;
                    $form->add('start_time', get_class($config->getType()->getInnerType()), $options);
    
                    $config = $form->get('end_time')->getConfig();
                    $options = $config->getOptions();
                    $options['disabled'] = true;
                    $form->add('end_time', get_class($config->getType()->getInnerType()), $options);
                }
            }
    
        }
    }
    
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>
March 31, 2016

Update schema for create longtext field on MySQL data base on symfony

Ehsan’s Question:

I want to update MySQL field from text to longtext using Doctrine schema.

Now my code is like this:

/**
 *@var string
 *@ORMColumn(name="head_fa", type="string", length=1000, nullable=true)
 */
private $head_fa;

/**
 *@var string
 *@ORMColumn(name="head_en", type="string", length=1000, nullable=true)
 */
private $head_en;

/**
 *@var string
 *@ORMColumn(name="body_fa", type="text", length=1000, nullable=true)
 */
private $body_fa;

/**
 *@var string
 *@ORMColumn(name="body_en", type="text", length=1000, nullable=true)
 */
private $body_en;

and the problem is when i change this field to this code

/**
 *@var string
 *@ORMColumn(name="head_fa", type="string", length=1000, nullable=true)
 */
private $head_fa;

/**
 *@var string
 *@ORMColumn(name="head_en", type="string", length=1000, nullable=true)
 */
private $head_en;

/**
 *@var string
 *@ORMColumn(name="body_fa", type="text", nullable=true)
 */
private $body_fa;

/**
 *@var string
 *@ORMColumn(name="body_en", type="text", nullable=true)
 */
private $body_en;

and run “php app/console doctrine:schema:update –force” command on console it said that “Nothing to update – your database is already in sync with the current entity metadata.” How to change this field to longtext on mysql database.

I do the same on different part of the project.
this is the code

/**
 * @ORMColumn(name="body", type="text", nullable=true)
 */
protected $body;

and after executing the “php app/console doctrine:schema:update –force” command on terminal this field is changed to longtext on MySQL database.

If you don’t specify a length parameter, it will automatically the column as LONGTEXT in MySQL.

How to make symfony forms support datetime-local input type?

Starx’s Question:

Most of the browsers are dropping support for datetime and also datetime-local as a valid input type. As of the time of writing this question, there are more support for support for datetime-local than datetime(which is almost non-existent).

If you building forms using Symfony’s form builder, it supports datetime but not datetime-local. So how would you make symfony form builder accept datetime-local input type and keep the rest of the functionality of the input type same?

One way this problem can be solved is, if we can change the text of input type to say datetime-local which can be done by overwriting the DateTimeType and using that.

<?php

namespace AppBundleComponentFormExtensionCoreType;

use SymfonyComponentFormFormInterface;
use SymfonyComponentFormFormView;

class DateTimeType extends SymfonyComponentFormExtensionCoreTypeDateTimeType
{
    /**
     * {@inheritdoc}
     */
    public function buildView(FormView $view, FormInterface $form, array $options)
    {
        $view->vars['widget'] = $options['widget'];

        // Change the input to a HTML5 datetime input if
        //  * the widget is set to "single_text"
        //  * the format matches the one expected by HTML5
        //  * the html5 is set to true
        if ($options['html5'] && 'single_text' === $options['widget'] && self::HTML5_FORMAT === $options['format']) {
            $view->vars['type'] = 'datetime-local';
        }
    }

}
August 31, 2015

Checking if an instance's class implements an interface?

Wilco’s Question:

Given a class instance, is it possible to determine if it implements a particular interface? As far as I know, there isn’t a built-in function to do this directly. What options do I have (if any)?

interface IInterface
{
}

class TheClass implements IInterface
{
}

$cls = new TheClass();
if ($cls instanceof IInterface)
    echo "yes"

You can use the “instanceof” operator. To use it, the left operand is a class instance and the right operand is an interface. It returns true if the object implements a particular interface.

You can also do the following

public function yourMethod(YourInterface $objectSupposedToBeImplementing) {
   //.....
}

It will throw an recoverable error if the $objectSupposedToBeImplementing does not implement YourInterface Interface.

June 30, 2015

How Can i copy a mysql record and save with different id using PHP?

Sunny’s Question:

I am new in PHP. I have an idea. Can i copy a recoed of table and save it with different id in same table?

For example i have a web form with different fields. I use that form to store data in database. Now i have a page where i display that record and use CRUD operations. When user click on Edit Button it goes on Form where he see a Button of Create copy. When user click on Create Copy button it just begin to start making a copy of selected data and store same data with different id?

create copy

Here is a simple way. You can have multiple submit buttons. Like

<input type="submit" name="submit" value="Edit" />
<input type="submit" name="submit" value="Make a copy" />

When this forms get submitted, you can check which submit button was pressed by asserting with $_POST['submit'] or $_GET['submit'] if you method is GET.

For example:

if($_POST['submit'] == 'Make a copy') {
    $action = "copy";
} elseif($_POST['submit'] == 'Edit') {
    $action = "edit";
}

Using that you can know what the user wanted to do. Since you already have the data, just pass those to your function which creates a new record without the primary key.

April 21, 2015

Extract Top Level Domain from Domain name

Joao Alves’s Question:

I have an array of top level domains like:

['ag', 'asia', 'asia_sunrise', 'com', 'com.ag', 'org.hn']

Given a domain name, how can i extract the top level domain of the domain name based on the array above? Basically i dont care of how many levels the domain has, i only need to extract the top level domain.

For example:

test1.ag -> should return ag

test2.com.ag -> should return com.ag

test.test2.com.ag -> should return com.ag

test3.org -> should return false

Thanks

Updated to incorporate Traxo’s point about the . wildcard; I think my answer is a little fuller so I’ll leave it up but we’ve both essentially come to the same solution.

//set up test variables
$aTLDList = ['ag', 'asia', 'asia_sunrise', 'com', 'com.ag', 'org.hn'];
$sDomain = "badgers.co.uk"; // for example

//build the match
$reMatch = '/^.*?.(' . str_replace('.', '.', implode('|', $aTLDList)) . ')$/';
$sMatchedTLD = preg_match($reMatch, $sDomain) ? 
        preg_replace($reMatch, "$1", $sDomain) : 
        "";

Resorting to Regular Expressions may be overkill but it makes for a concise example. This will give you either the TLD matched or an empty string in the $sMatchedTLD variable.

The trick is to make the first .* match ungreedy (.*?) otherwise badgers.com.ag will match ag rather than com.ag.

parseurl() function gives you access to the host name of the url. You can use that to process the host name and find out the tld.

$url = 'http://your.url.com.np';
var_dump(parse_url($url, PHP_URL_HOST));

Next steps could be using explode() to split the host name and checking the last item in the exploded list. But I am going to leave that to you.

September 29, 2013

insert &lt;/br&gt; after comma with php

Vektor’s Question:

I array text from custom field “black, grey, white” with this code:

<?php global $wp_query; $postid = $wp_query->post->ID; echo get_post_meta($postid, 'colors', true); ?>

I want show me like this:

black</br>
grey</br>
white

It’s possible with PHP? Many thanks

Use str_replace():

echo str_replace(",", "<br />", get_post_meta($postid, 'colors', true));

Log in script load users name

User2827404’s Question:

ive just built a php and mysql log in script which forwards to a members area. I now want the members name that loged in to be displayed, somthing like welcome Stephen for example.

what would be the best way to do this?

ok this is my code once the submit button has been pressed:

`<?php

$host="localhost"; // Host name
$username="stephen2_phptest"; // Mysql username
$password="********"; // Mysql password
$db_name="stephen2_phptest"; // Database name
$tbl_name="registers"; // Table name

// Connect to server and select databse.
mysql_connect("$host", "$username", "$password")or die("cannot connect");
mysql_select_db("$db_name")or die("cannot select DB");

// username and password sent from form
$myusername=$_POST['myusername'];
$mypassword=$_POST['mypassword'];


// To protect MySQL injection (more detail about MySQL injection)
$myusername = stripslashes($myusername);
$mypassword = stripslashes($mypassword);
$myusername = mysql_real_escape_string($myusername);
$mypassword = mysql_real_escape_string($mypassword);

$sql="SELECT * FROM registers WHERE email='$myusername' and password='$mypassword'";
$result=mysql_query($sql);

// Mysql_num_row is counting table row
$count=mysql_num_rows($result);

// If result matched $myusername and $mypassword, table row must be 1 row

if($count==1){

// Register $myusername, $mypassword and redirect to file "login_success.php"
session_register("myusername");
session_register("mypassword");
header("location:members.php");
}
else {
echo "Wrong Username or Password";
}
?>`

And this is the code for the members area:

`<?php

$host="localhost"; // Host name
$username="stephen2_phptest"; // Mysql username
$password="********"; // Mysql password
$db_name="stephen2_phptest"; // Database name
$tbl_name="registers"; // Table name

// Connect to server and select databse.
mysql_connect("$host", "$username", "$password")or die("cannot connect");
mysql_select_db("$db_name")or die("cannot select DB");
session_start();
if(!session_is_registered(myusername)){
header("location:index.php");

$myusername=$_POST['myusername'];
}
?>
<html>
<link rel="stylesheet" type="text/css" href="../php/css/styles.css">
<body>
    <div class="members-screen">
Login Successful</br>
Welcome [persons name to load here]<?php echo $_POST['myusername'] ?> <a href="../php/logout.php"> | Logout</a>
<div class="menu">
    <div class="menu-btn">
        <a href="">Home</a>
        </div>
        <div class="menu-btn">
            <a href="">Search</a>
            </div>
            <div class="menu-btn">
                <a href="">Messages</a>
                </div>
                <div class="menu-btn">
                    <a href="">Matches</a>
                    </div>
                    <div class="menu-btn">
                        <a href="">My Account</a>
                        </div>
    </div>
</div>
</body>
</html>`

Store the name on the session when the user logs in and use it when it is needed to be showed.

session_start();

// Your login process

if($valid == true) {
   $_SESSION['logged_user'] = 'stephen'; // Fetch name from database
}

Then where you need to show:

session_start();
echo $_SESSION['logged_user'];
September 17, 2013

How to replace session_register() for PHP 5.4+

Michael Curving’s Question:

out of the blue I was getting the following error when logging in to one of my sites:

Call to undefined function session_register()

After some research I saw that session_register() is deprecated after PHP 5.4. I checked in my hosting control panel, and sure enough it says current version I’m running is PHP 5.4.19. I assume they just forced an upgrade which is why this problem seemed to occur out of the blue.

I looked through several Stack Overflow posts and reviewed links to PHP documentation. From what I gather, session_register() is deprecated and should be replaced with $_SESSION instead.

Problem is, both of those already appear in my code. Here is the code in my index.php file:

  53 <? if ($username) {
  54    session_register("ADMIN");
  55    $_SESSION['ADMIN'] = $username;
  56 ?>

So I hoped just by removing line 54 (the deprecated piece) then it should work, however that is not the case. It broke the code when I did that.

Based on other posts I read HERE and HERE they seem to be saying that the code I see in line 55 above should by itself do the trick. So I’m a bit confused why it didn’t work. If anyone can tell me what code I should use I would sincerely appreciate it. The developer of the script is not really offering support.

NOTE: Also, yes there is session_start() called at the very top of the page.

Add a session_start() at the begining of your code and $_SESSION to manipulate it or create it.

...

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