Having Trouble implementing QR code in cakephp

Hellow i am having trouble implementing qr code that will read the database data on my cakephp 4.

i’ve been searching for tutorial in Youtube about implementing qrcode (https://youtu.be/TXYlfmK-MsM?si=_zi0gtseDbG8xTv9) by alimon pito. but the repository has been removed.

i would be glad if there can be someone who can give me advice on qr code in cakephp. thank you so much!

There is nothing really CakePHP specific you need here, so just use a generic PHP package like:

1 Like

Hellow thank you for having time to reply to my post. what would be better to use the chillerlan or endroid? what i’m trying to do is that inside my view it would automatically create a qr code based on the information inside the database. thank you for your time and any further advice would be so much help for me.

I’ve try to use using the advise you said and when i don’t comment the catch i won’t be redirect and if i do comment the catch and get redirected there isn’t a qr code generated. heres my code:

namespace App\Controller;

public function view($id = null)
    {
        try {
            $rider = $this->Riders->get($id, [
                'contain' => [],
            ]);
            $this->Authorization->authorize($rider); //Authorization needed to perform action
            $data = ($rider->first_name);

            // quick and simple:
            $image_qrCode = '<img src="'.(new QRCode)->render($data).'" alt="QR Code" />';

        } catch (\Throwable $th) {
            //$this->Flash->error('Sorry only Admin is allowed to view riders');
            //return $this->redirect(['action' => 'index']);
        }
        
        $this->set(compact('rider', 'image_qrCode'));
    }

I don’t really understand how it goes. I would be very thankful if you could help me kind sir.

let me just explain it step by step

composer require chillerlan/php-qrcode to add the package to your app

then add this to any controller action

$imgSrc = (new \chillerlan\QRCode\QRCode)->render('thisissomerandomdata');
$this->set(compact('imgSrc'));

I just used the FQCN of that QRCode class instead of using a use statement at the top of the class. If you don’t know what namespaces are check out my Youtube video from 2 years ago

and in your template you can then do

<img src="<?= $imgSrc ?>" alt="QR Code" />

which will then render this QR code if you call your controller action
image

The only “non CakePHP specific” thing here is

$imgSrc = (new \chillerlan\QRCode\QRCode)->render('thisissomerandomdata');

everything else is default MVC behaviour where you generate/fetch data in your controller and pass it onto the view/template to render it.

hellow thank you for having time to reply on my message. Your advice was helpful to me and also the video i have just watched it and installed your recommended vscode extensions. i also updated my codes

public function view($id = null)
    {
        try {
            $rider = $this->Riders->get($id, [
                'contain' => [],
            ]);
            $this->Authorization->authorize($rider); // Authorization needed to perform action
    
            $imgSrc = (new \chillerlan\QRCode\QRCode)->render('rider');
            
            $this->set(compact('imgSrc'));
        } catch (\Throwable $th) {
            $this->Flash->error('Sorry only Admin is allowed to view riders');
            return $this->redirect(['action' => 'index']);
        }
    
        $this->set(compact('rider'));

But still when i go to the view i still get the flash error and when i commented it and the return. inside my view will have a error in the img.

[ Warning (2) ](javascript:void(0);): Undefined variable $imgSrc [in D:\Applications\XAMPP\htdocs\CQS\templates\Riders\view.php , line 51 ] " alt=“QR Code” />

its still the same even if i use the use chillerlan\QRCode\QRCode; bellow the namespace. I’m sorry for troubling you more. But i don’t know why it will still behaving like this.

Well this probably means your

$this->Authorization->authorize($rider);

is throwing an exception because your Policy for that action doesn’t allow the current user to do this.

Undefined variable $imgSrc means $this->set(compact('imgSrc')); was not called.

When an exception is thrown all the code after that point won’t be executed (till the next try-catch block). I’d recommend try to get it working without the authorization checks and then go back to narrowing your controller action down to the specific users you want.

Hellow thank you for having time to reply to my post.

What i decided to do is create a function

public function generateQRCode($id = null)
    {
        $rider = $this->Riders->get($id, [
            'contain' => [],
        ]);

        $riderData = [
            'id' => $rider->id,
            'First Name' => $rider->first_name,
            'Last Name' => $rider->last_name,
            
        ];

         // Convert the rider data to a JSON string
        $data = json_encode($riderData);

        // Generate the QR code
        $imgSrc = (new \chillerlan\QRCode\QRCode)->render($data);

        $this->set(compact('imgSrc'));
    }

and in the view i set this.

<img src="<?= $this->Url->build(['controller' => 'Riders', 'action' => 'generateQRCode', $rider->id]) ?>" alt="QR Code" />

I’ve still not rendered an image. i’ve also tried your advice on the policy but I’ve gotten no luck on that. :exploding_head: i dunno what to do.

why are you now trying to build a URL to the controller action as part of the src attribute of a image? You are mixing things up here.

(new \chillerlan\QRCode\QRCode)->render($data);

returns a string which should directly be put inside the src attribute.

So just do

<img src="<?= $imgSrc ?>" alt="QR Code" />

as already described above and you should be fine

Hellow good day. i have done what you asked but it still won’t work. here’s my full code

namespace App\Controller;

use chillerlan\QRCode\QRCode;

/**
 * Riders Controller
 *
 * @method \App\Model\Entity\Rider[]|\Cake\Datasource\ResultSetInterface paginate($object = null, array $settings = [])
 */
class RidersController extends AppController
{

     // in src/Controller/UsersController.php
     public function beforeFilter(\Cake\Event\EventInterface $event)
     {
         parent::beforeFilter($event);
 
         $this->Authentication->allowUnauthenticated(['login']);
     }    
    
    /**
     * Index method
     *
     * @return \Cake\Http\Response|null|void Renders view
     */
    public function index()
    {
        //use for skipping the authorization making anyone view the contents
        $this->Authorization->skipAuthorization(); 
        
        $riders = $this->paginate($this->Riders);

        $this->set(compact('riders'));
    }

    /**
     * View method
     *
     * @param string|null $id Rider id.
     * @return \Cake\Http\Response|null|void Renders view
     * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found.
     */
    public function view($id = null)
    {
        try {
            $rider = $this->Riders->get($id, [
                'contain' => [],
            ]);
            $this->Authorization->authorize($rider); // Authorization needed to perform action
        } catch (\Throwable $th) {
            $this->Flash->error('Sorry only Admin is allowed to view riders');
            return $this->redirect(['action' => 'index']);
        }
    
        $this->set(compact('rider'));
    }

    /**
     * Add method
     *
     * @return \Cake\Http\Response|null|void Redirects on successful add, renders view otherwise.
     */
    public function add()
    {
        $rider = $this->Riders->newEmptyEntity();
        //this "try/catch" code will prevent users for accidentally doing something that its not authorized.
        //but you must put false in the policy
        try {
            $this->Authorization->authorize($rider); //Authorization needed to perform action
            if ($this->request->is('post')) {
                $rider = $this->Riders->patchEntity($rider, $this->request->getData());
                if ($this->Riders->save($rider)) {
                    $this->Flash->success(__('The rider has been saved.'));

                    return $this->redirect(['action' => 'index']);
                }
                $this->Flash->error(__('The rider could not be saved. Please, try again.'));
            }
        } catch (\Throwable $th) {
            $this->Flash->error('Sorry only Admin is allowed to add riders');
            return $this->redirect(['action' => 'index']);
        }
        
        $this->set(compact('rider'));
    }

    /**
     * Edit method
     *
     * @param string|null $id Rider id.
     * @return \Cake\Http\Response|null|void Redirects on successful edit, renders view otherwise.
     * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found.
     */
    public function edit($id = null)
    {
        $rider = $this->Riders->get($id, [
            'contain' => [],
        ]);
        //this "try/catch" code will prevent users for accidentally doing something that its not authorized.
        //but you must put false in the policy
        try {
            $this->Authorization->authorize($rider); //Authorization needed to perform action
            if ($this->request->is(['patch', 'post', 'put'])) {
                $rider = $this->Riders->patchEntity($rider, $this->request->getData());
                if ($this->Riders->save($rider)) {
                    $this->Flash->success(__('Rider Changes has been saved.'));
    
                    return $this->redirect(['action' => 'index']);
                }
                $this->Flash->error(__('The changes could not be saved. Please, try again.'));
            }
        } catch (\Throwable $th) {
            $this->Flash->error('Sorry only Admin is allowed to edit riders');
            return $this->redirect(['action' => 'index']);
        }
        
        $this->set(compact('rider'));
    }

    /**
     * Delete method
     *
     * @param string|null $id Rider id.
     * @return \Cake\Http\Response|null|void Redirects to index.
     * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found.
     */
    public function delete($id = null)
    {
        $this->request->allowMethod(['post', 'delete']);
        $rider = $this->Riders->get($id);
        //this "try/catch" code will prevent users for accidentally doing something that its not authorized.
        //but you must put false in the policy
        try {
            $this->Authorization->authorize($rider); //Authorization needed to perform action
            if ($this->Riders->delete($rider)) {
                $this->Flash->success(__('The rider has been deleted.'));
            } else {
                $this->Flash->error(__('The rider could not be deleted. Please, try again.'));
            }
        } catch (\Throwable $th) {
            $this->Flash->error('Sorry only Admin is allowed to delete riders or Current Rider is active on Queue. Please Check!');
            return $this->redirect(['action' => 'index']);
        }
       

        return $this->redirect(['action' => 'index']);
    }

    // Logout Function
    public function logout()
    {
        //use for skipping the authorization making anyone view the contents
        $this->Authorization->skipAuthorization();
         
        $this->Authentication->logout();
        return $this->redirect(['controller' => 'Homepages', 'action' => 'homepage']);
    }

    public function generateQRCode($id = null)
    {
        $rider = $this->Riders->get($id, [
            'contain' => [],
        ]);

        // Check if the current user can generate a QR code for this rider
        $this->Authorization->authorize($rider, 'cangenerateQRCode');
        
        $riderData = [
            'id' => $rider->id,
            'First Name' => $rider->first_name,
            'Last Name' => $rider->last_name,
            
        ];

         // Convert the rider data to a JSON string
        $riderData = json_encode($riderData);

        // Generate the QR code
        $imgSrc = (new QRCode)->render($riderData);
        debug($imgSrc);
        $this->set(compact('imgSrc'));
    }
}

in the policy

namespace App\Policy;

use App\Model\Entity\Rider;
use Authorization\IdentityInterface;

/**
 * Rider policy
 */
class RiderPolicy
{
    /**
     * Check if $user can add Rider
     *
     * @param \Authorization\IdentityInterface $user The user.
     * @param \App\Model\Entity\Rider $rider
     * @return bool
     */
    public function canAdd(IdentityInterface $user, Rider $rider)
    {
        if ($user->role === 'Admin' || $user->role === 'admin') {
            return true;
        } else {
            return false;
        }
    }

    /**
     * Check if $user can edit Rider
     *
     * @param \Authorization\IdentityInterface $user The user.
     * @param \App\Model\Entity\Rider $rider
     * @return bool
     */
    public function canEdit(IdentityInterface $user, Rider $rider)
    {
        if ($user->role === 'Admin' || $user->role === 'admin') {
            return true;
        } else {
            return false;
        }
    }

    /**
     * Check if $user can delete Rider
     *
     * @param \Authorization\IdentityInterface $user The user.
     * @param \App\Model\Entity\Rider $rider
     * @return bool
     */
    public function canDelete(IdentityInterface $user, Rider $rider)
    {
        if ($user->role === 'Admin' || $user->role === 'admin') {
            return true;
        } else {
            return false;
        }
    }

    /**
     * Check if $user can view Rider
     *
     * @param \Authorization\IdentityInterface $user The user.
     * @param \App\Model\Entity\Rider $rider
     * @return bool
     */
    public function canView(IdentityInterface $user, Rider $rider)
    {
        if ($user->role === 'Admin' || $user->role === 'admin') {
            return true;
        } else {
            return false;
        }
    }

    public function cangenerateQRCode(IdentityInterface $user, Rider $rider)
    {
        if ($user->role === 'Admin' || $user->role === 'admin') {
            return true;
        } else {
            return false;
        }
    }
}

and in the view

<div class="column-responsive column-80">
        <div class="riders view content">
            <table>
                <tr>
                <img src="<?/the code/= $imgSrc ?>" alt="QR Code" />
                    <th><?= __('First Name') ?></th>
                    <td><?= h($rider->first_name) ?></td>
                </tr>
                <tr>
                    <th><?= __('Last Name') ?></th>
                    <td><?= h($rider->last_name) ?></td>
                </tr>
                <tr>
                    <th><?= __('Address') ?></th>
                    <td><?= h($rider->address) ?></td>
                </tr>
                <tr>
                    <th><?= __('Id') ?></th>
                    <td><?= $this->Number->format($rider->id) ?></td>
                </tr>
                <tr>
                    <th><?= __('Contact') ?></th>
                    <td><?= h($rider->contact) ?></td>
                </tr>
                <tr>
                    <th><?= __('Brand') ?></th>
                    <td><?= h($rider->brand) ?></td>
                </tr>
                <tr>
                    <th><?= __('Model') ?></th>
                    <td><?= h($rider->model) ?></td>
                </tr>
                <tr>
                    <th><?= __('Plate #') ?></th>
                    <td><?= h($rider->plate) ?></td>
                </tr>
            </table>
        </div>
    </div>
</div>

also I’ve been having trouble for the cake php here in my screen. it’s not like the first that i can have those console from cake here is the image.

it became so small i could hardly read anything inside the box.

Im sorry for being troublesome. I just don’t know how to get through this problem myself.

what URL are you calling. Do you call http://localhost/riders/generateQRCode/1 or something like that?
Its not clear what controller action you are calling and therefore which template you are rendering.

The reason why I ask this is because you have debug($imgSrc); in your controller action but it doesn’t show in your screenshot. This means you are not calling that generateQRCode($id = null) method


The DebugKit error problem in your screenshot is mostly because you didn’t add

    'DebugKit' => [
        'ignoreAuthorization' => true
    ],

to your config/app_local.php

See Debug Kit - 4.x

1 Like

I’m sorry for not saying what url i’m calling. here’s the flow of my system.

after i log in i would be at http://localhost:8765/riders and then i pick a rider and I’m gonna be at http://localhost:8765/riders/view/11. i would like to render the qr code there so that when i view the rider details the qr code will read the first_name and last_name from the database riders tables and generate it’s qr code. im using bin\cake server.

I’m very thankful for the time you spent replying to my problem and thank you for the debug kit code in your last message. it fix my probem in the screenshot.

Thank you for all of your advice. I have solved my problem. it seems that i need to add the “extension=php_gd2.dll” to the php.ini so that i could generate the image. I’ve used endroid/qr-code for this. thank you so much sir KevinPfeifer i couldn’t have solve this without your advice.