February 22, 2019

Why supervisord does not log my PHP CLI fwrite(STDOUT, "message")?

Albert’s Question:

I have a PHP command line application ( zconsole awswebhookrunner ) run by supervisord.

Supervisord does not log on the files fwrite(STDOUT, "message") but it does log echo "message".

Supervisord config

[program:aws_webhook]
command=/home/(username)/bin/zconsole awswebhookrunner
process_name=%(program_name)s_%(process_num)02d
numprocs=1
directory=/tmp
priority=999
autostart=true
autorestart=true
startretries=100
stopwaitsecs=10
user=(username)
stdout_logfile=/home/(username)/logs/aws_webhook_runner.out.log
stderr_logfile=/home/(username)/logs/aws_webhook_runner.err.log
stdout_logfile_maxbytes=10MB

PHP Code

private function log($message, $type="info")
{
    $output=STDIN;
    switch ($type) {
        case "error":
            $output=STDERR;
            break;
        default:
            $output=STDIN;
    }
    $to_log=date("Y-m-d H:i:s")." ".$message;
    fwrite($output,$to_log.PHP_EOL) ;
    //echo $to_log.PHP_EOL;
    fflush($output);
    unset($to_log);
}

Software version

PHP version: 5.3.3
OS: CentOS 6.10
supervisord: 3.3.5

Questions

  1. Is my supervisord setup correct?
  2. Do I have a misunderstood the behavior of fwrite(STDOUT|STDERR, $message);?
  3. Why echo $message; works if it is sent to STDOUT?
  1. Configuration wise, I think it is fine. Command-wise, it’s a different question really.
  2. You are trying to STDIN rather than STDOUT. STDIN is used for input supervisord does not deal with STDIN I think.
  3. echo would print to STDOUT because it is its default behavior.
June 28, 2017

Auto version your JavaScript or Stylesheet files using .htaccess

Usually, developers can maintain the cache they maintain themselves at the backend but cannot control the cache held by the browser as freely as they want unless there is proper version control. Here is a quick drop in solution in `.htaccess` file until you have proper versioning.

Most of the applications have one or many layers of cache for their system. The cache that application developer can maintain is at the backend (the server) level. However, you cannot control the cache held by the browser as freely as you want unless you version the files as well.

Versioning the files is definitely the best way to solve this problem because it is a very efficient solution which guarantees that browser will fetch the new resource when you want it to. But there are cases where this is not an easy step to be taken, for example, in a legacy app which resources are included in line the page.

So, is there a quick way to fix the problem until you go to proper versioning?

Yes! there is.

Using .htaccess we can auto version the files and force the browser to fetch files down to every second if we need to.

Here is how:

We can use server variables such as TIME_YEAR, TIME_MONTH to create an automatic version of your resource. These are variables that the web server provide to be used where suitable. And now, let’s see how to do this.

RewriteCond %{QUERY_STRING} !(v=(.<em>))
Rewriterule ^(js|scripts|css|styles)(.</em>)$ /$1$2?v=%{TIME_YEAR}%{TIME_MON}%{TIME_DAY}%{TIME_HOUR} [r=302,nc]`

Open your .htaccess files and paste those two lines in. What these are doing is:

  • If a request comes to the server that starts with js, scripts, css or styles then rewrite the request by appending an auto-created version at the end.
  • IF a request comes with the version already in the request then don’t do anything because we don’t want it to keep rewriting the request.

Simple as that. So for example: if the request comes to https://abc.com/js/main.js it gets served as https://abc.com/js/main.js?v=2017062811. Same goes for any request coming to other paths as well. This example ensures that browser will fetch the resource again every hour. But if you add variables like TIME_MINUTE or TIME_SECOND or TIME browser will keep fetching the content more frequently.

To see what other server variables can be used visit https://httpd.apache.org/docs/trunk/expr.html#vars

March 4, 2017

MAX in PHP returning wrong value

Krish’s Question:

I have an array with key and value pair. I’m building this array dynamically and below is the code.

$x[] = array('type_name' => $value->name,
            'percentage'=> intval($percentage));

My intention is to get the maximum value and for that I do

max($x);

However it is returning the wrong value actually the lowest value. Following is my array. Any help would be awesome.

Thanks is advance.

You need to read how the max compares against different types of data. In your case, you are trying to compare against one of the array item i.e. percentage inside one of the item so the function max does not know to do this.

There is an example by Revo in the manual which shows you how to do this.

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.

...

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