Category Archives for php

Create related data with Pest, Laravel and factories

Setting up the related testdata when creating Pest tests always keeps me searching for the syntax.
Therefore, here a little reminder to self with links to the appropriate info in the Laravel documentation.

HasMany relations: User hasMany Post

// hasMany relation: User has many Posts - post.user_id is set
$user = User::factory()
  ->has(Post::factory()->count(3))
  ->create();

BelongsTo relations (inverse of the hasMany): Post belongsTo User => for()

// belongsTo: post.user_id is set
$post = Post::factory()
  ->for(User::factory())
  ->create();

Many to Many: User belongsToMany Role => has() and hasAttached()

// belongsToMany: using the pivot table. NOTE the array as first argument!
$user = User::factory()
  ->hasAttached([$tag], [<pivot fields>], 'roles')
  ->create();

Browscap with PHP

In order to get info about your clients browser, you need to install browscap.

ERROR: get_browser(): browscap ini directive not set

NOTE: you get this same error for different reasons! Check your logfiles to figure out what is the real reason for this error.

Reasons I encountered:

Browscap was not installed

To install Browscap on my Ubuntu (Docker image), I used the following site browscap.org.

It comes down to:

  1. download the ini file
  2. update (the correct! => fpm) php.ini file to load browscap
  3. restart the webserver

In the terminal (or in your Dockerfile):

# install browscap to get browser information of the client
curl https://browscap.org/stream?q=PHP_BrowsCapINI --output ${PHPDIR}/mods-available/php_browscap.ini

# add it to php.ini under the [browscap] directive
sed -i "s|;browscap = extra/browscap.ini.*|browscap = \"${PHPDIR}/mods-available/php_browscap.ini\"|g" ${PHPDIR}/fpm/php.ini

Browscap ini file was not included in php.ini

You can check whether PHP found the browscap file by

  • ensuring you entered the correct path to the file in the step above
  • ensuring the webserver has read permissions for the file
  • place phpinfo() on a page and search for browscap. It should be mentioned there
browscap mentioned in phpinfo()

Calling get_browser() with the wrong arguments

This is a funky one as the ini directive is set.

A look at the laravel log helped: get_browser(): HTTP_USER_AGENT variable is not set, cannot determine user agent name

I used get_browser(null, true) as I found in an online example, but it really needs the user agent as the first argument.

I fixed it by using: `

get_browser($request->userAgent(), true)

Note that I use Laravel, hence the $request->userAgent(). You can replace this with $_SERVER['HTTP_USER_AGENT'] just as well.

Other useful links

If this didn’t work out, you might info about your usecase somewhere on these pages:

Laravel order records by days until date – like the next birthday

You might want to order your users by ‘days until their birthday’.

People having their birthday come first, people with no birthday registered (NULL values), come last.

// in User model
public static function getByBirthday()
{
  return User::query()
      ->select('user.*')
      ->selectRaw(
          '365.25 -
          (
            case
              WHEN TIMESTAMPDIFF(day, birthday, CURDATE()) = 0 THEN 364.25
              WHEN birthday IS NULL THEN 0
              ELSE TIMESTAMPDIFF(day, birthday, CURDATE())
            end
            mod 365.25
           ) AS days_till_birthday'
      )
      ->orderBy('days_till_birthday');
}

// use it in your code like
$usersByBirthday = User::getByBirthday()->get();

MySQL fix timestamps for laravel

Execute the following queries to have your ‘created_at’ column the current timestamp upon creation and your ‘updated_at’ the current timestamp upon modification.

// set the default values
DB::statement("ALTER TABLE $table CHANGE created_at created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP")
DB::statement("ALTER TABLE $table CHANGE updated_at updated_at TIMESTAMP NULL ON UPDATE CURRENT_TIMESTAMP");

Posting a form results in 502 error on PHP, nginx and xdebug

This error broke my head the other day.

Whenever I posted a specific form, I got a 502 error.

I only got it to work when I disabled (as in: rebuild Docker image to not contain) xdebug.

When I posted the form, there was this warning: PHP Warning: Unknown: Input variables exceeded 1000.

A quick search learned that I could set the PHP option max_input_vars to 3000. This made the whole thing working again so I could focus on why this big form has more than 1000 input vars….

; file xdebug.ini

;comment all to disable xdebug
;zend_extension="xdebug.so"
;xdebug.mode=debug,coverage
;xdebug.client_host=host.docker.internal
;xdebug.client_port=9003
;xdebug.start_with_request=trigger

; set PHP directive to allow for maximum 3000 input vars
; PHP Input Vars is a PHP security measure designed to limit the number 
; of post variables you can use to execute a function. It defines the 
; number of variables your server can use when running a function.
max_input_vars = 3000

Laravel API returns 401 even while logging in succeeds

For me, it turned out the stateful property in config/sanctum.php was not filled correctly.

After setting it to the default as shown below, it started working.

// file config/sanctum.php
...
    'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
        '%s%s',
        'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1',
        Sanctum::currentApplicationUrlWithPort()
    ))),
...

Did this not fix your problem?

Check this post which might help: https://stackoverflow.com/a/69858100

Install Gearman from source on Ubuntu 18.04

I tried to install Gearman on my Ubuntu 18.04 Docker container and encountered a lot of issues.

This write-up is to save you some valuable time of your life.

TL;DR

apt update
apt install -y g++ uuid-dev gperf libboost-all-dev libevent-dev curl 

cd /tmp
curl -LO https://github.com/gearman/gearmand/releases/download/1.1.18/gearmand-1.1.18.tar.gz
tar xvzf gearmand-1.1.18.tar.gz
cd gearmand-1.1.18
./configure --with-boost-libdir=/usr/lib/x86_64-linux-gnu
make
make test
make install

# Start gearman in the background
gearmand --log-file /var/log/gearmand.log --daemon

To get there, I encountered the following issues:

configure: error: Unable to find libevent

./configure --with-boost-libdir=/usr/lib/x86_64-linux-gnu
...
checking test for a working libevent... no
configure: error: Unable to find libevent

Fix: apt install -y libevent-dev

configure: error: Could not find a version of the library!

./configure --with-boost-libdir=/usr/lib/x86_64-linux-gnu
...
checking whether the Boost::Program_Options library is available... yes
configure: error: Could not find a version of the library!

Fix: apt install -y libboost-all-dev

Installing the PHP client libraries for Gearman

If you intend to use PHP to talk to your Gearman service, use the following to get the libraries installed.

Note: you might not need the last line. This is to enable the Gearman PHP extension in Docker.

cd /tmp \
  && wget https://github.com/wcgallego/pecl-gearman/archive/gearman-2.0.6.tar.gz\
  && tar xvzf gearman-2.0.6.tar.gz \
  && mv pecl-gearman-gearman-2.0.6 pecl-gearman \
  && cd pecl-gearman \
  && phpize \
  && ./configure \
  && make -j$(nproc) \
  && make install \
  && cd / \
  && rm /tmp/gearman-2.0.6.tar.gz \
  && rm -r /tmp/pecl-gearman \
  && docker-php-ext-enable gearman

Slim 2 framework logging

This shows you how to enable logging so you can write stuff like $app->log->debug('this will show up in the error_log');.

<?php

--- snip %< ---

$app = new \Slim\Slim(array(
    'log.enabled' => true,
    'log.level'   => \Slim\Log::DEBUG
));

$app->log->debug('this will show up in your error-log');

--- >% /snip ---

 

[opt-in]

XDebug for PHPUnit in Docker with PHPStorm

[ update ]
Set the IP-address to the following DNS-name: docker.for.mac.localhost (yes, literally)!
Working with the IP-address doesn’t work anymore
[ /update ]

Want to get XDebug working for your PHPUnit tests which run in Docker? Or for behat? Or any other CLI application? Follow me!

Roughly this is what you’ll need to do: Continue reading