Stuff I'm Up To

Technical Ramblings

[unixODBC][Driver Manager]Can’t open lib : file not found — July 12, 2019

[unixODBC][Driver Manager]Can’t open lib : file not found

I have no idea how we came up against this issue on one of the development images. I’d prepared it all up to the point of delivering php. After following my instructions to install the MS SQL drivers everything looked to go well, but when serving up our Laravel project in artisan PHP came up with this error message.

[unixODBC][Driver Manager]Can’t open lib ‘/opt/microsoft/msodbcsql17/lib64/libmsodbcsql-17.3.so.1.1’ : file not found

Now we have seen this before and it related to locale’s so we tried that fix and still didn’t get it to work.

Trawling the internet I came across something pointed us to use ldd to look at the .so file and check out it’s dependencies.

Continue reading
Advertisements
PHP 7.1 and MSSQL Compile Issue — July 8, 2019

PHP 7.1 and MSSQL Compile Issue

When trying to get PHP v7.1 running on a Debian Buster development box I ran into an issue where pecl would compile the sqlsrv.so and pdo_sqlsrv.so files for the wrong version of PHP.

It didn’t seem obvious what was going on at first. I went through the very good Microsoft ODBC for Linux installer guide and things went well up until pecl delivered the drivers.

Continue reading
Laravel Caching Indefinitely — June 28, 2019

Laravel Caching Indefinitely

I recently attended the Laravel UK conference and learned a lot of very useful things. One of them related to a caching methodology being used for data that rarely changes.

Up until now I’d been taking best guesses to how long to cache data for on a case by case basis. In one particular example I reckoned 8 hours was about right as the data only really changed once every 3 months or less.

This still caught me out as on the day the user did change the underlying data the api call was still responding with cached data and would do so until the 8 hours expired. The user experience then meant they’d need to wait until tomorrow before others would see they’d made a change.

This wasn’t ideal. So how do we best satisfy the users with up to date data?

Continue reading
VS Code Extensions — May 31, 2019

VS Code Extensions

I’m an Atom fan and have used it on Linux for ages. I probably still will, but our other developers tend to use VS Code because of their use of MS Windows. I thought I’d revisit VS Code and see if I can use it effectively like Atom.

First thing I needed to make sure of was that some of the Atom features I use are available in VS Code. Standard stuff like dark colour theme, ESLint, syntax highlighting, auto-completions and Emmet.

One pleasant surprise was that VS Code has Emmet built right in! The usage is a little different, keyboard shortcuts etc. but it’s native to VS Code so that’s pretty good.

Other Extensions that I’ve added to support the languages I use are:

Vetur – https://vuejs.github.io/vetur/

ESLint – https://github.com/Microsoft/vscode-eslint

Toggle Excluded Files – https://marketplace.visualstudio.com/items?itemName=eamodio.toggle-excluded-files

Bracket Pair Colorizer – https://marketplace.visualstudio.com/items?itemName=CoenraadS.bracket-pair-colorizer

phpcs – https://github.com/ikappas/vscode-phpcs requires PHP CodeSniffer

PHP DocBlocker – https://github.com/neild3r/vscode-php-docblocker

FiraCode font https://github.com/tonsky/FiraCode

rest-client https://marketplace.visualstudio.com/items?itemName=humao.rest-client

PHPUnit – Version Mismatch — February 4, 2019

PHPUnit – Version Mismatch

As our codebase matures we return to develop unit tests to ensure our QA process captures any code changes that may have altered the functionality of the product.

When calling PHPUnit on Windows or Linux we ran into some issues relating to the version of PHPUnit we had installed.

On Windows it was an ancient PHPUnit version 3 and on Linux It was running version 7. Neither of which were compatible with our Laravel 5.5 project which uses php version 7.0.

In order to use PHPUnit with our project we must use PHPUnit version 6 (see Supported Versions)

What I hadn’t realised is that we had installed PHPUnit both locally into the OS and with our Laravel project so it exists in composer.json and gets installed under the projects ./vendor. The version installed in the OS path is the version that isn’t compatible with our project, but because it’s in our path it’s taking precedence over our project installed version.

To run the project version we just need to be specific in how we call it.

$ ./vendor/phpunit/phpunit/phpunit
PHPUnit 6.5.13 by Sebastian Bergmann and contributors.

....F                                                               5 / 5 (100%)

Time: 345 ms, Memory: 16.00MB

There was 1 failure:

1) Tests\Unit\Finance\CostCodeTest::testApiGetCostCodes
Expected status code 401 but received 200.
Failed asserting that false is true.

/home/user/itsm/vendor/laravel/framework/src/Illuminate/Foundation/Testing/TestResponse.php:78
/home/user/itsm/tests/Unit/Finance/CostCodeTest.php:37

FAILURES!
Tests: 5, Assertions: 14, Failures: 1.

php 7.0 on Debian Buster — January 2, 2019

php 7.0 on Debian Buster

Actually this is more about any version of php (5.6, 7.0, 7.1, 7.2) on buster. Php source has taken on a bit of a split and the standard repositories only deal with the one supported version for the current release of Debian you are using.

This means that on Debian 9 (buster/sid) the only version available from the Debian repository is php 7.3.

Our current production systems are Debian 9 stretch and only support php 7.0 and therefore only Laravel 5.5. In order to bring my development platform down to php 7.0 I must use a non-standard repository.

Ondřej Surý has been packaging php for Debian and Ubuntu and distributing them. To get them you need to add his key and repository into your aptitude:

$ wget -q https://packages.sury.org/php/apt.gpg -O- | sudo apt-key add -
$ echo "deb https://packages.sury.org/php/ stretch main" | sudo tee /etc/apt/sources.list.d/php.list

Now you can add in whatever version of php you’d like even 5.6. eg.

$ sudo apt-get install php7.0-fpm php7.0-mbstring php7.0-zip php7.0-mysql php7.0-sqlite3 php7.0-dev php-pear

If you already had 7.3 installed nothing will have changed yet and when you type php from the command line you’ll see it still runs version 7.3.

$ php -v

PHP 7.3.0-2+0~20181217092659.24+stretch~1.gbp54e52f (cli) (built: Dec 17 2018 09:26:59) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.3.0-dev, Copyright (c) 1998-2018 Zend Technologies
with Zend OPcache v7.3.0-2+0~20181217092659.24+stretch~1.gbp54e52f, Copyright (c) 1999-2018, by Zend Technologies

To switch back to 7.0 use the following and you’ll see your php go back to 7.0. Switch back in the same way, but replace 7.0 with 7.3.

$ sudo update-alternatives --set php /usr/bin/php7.0

update-alternatives: using /usr/bin/php7.0 to provide /usr/bin/php (php) in manual mode
$ php -v

PHP 7.0.33-1+0~20181208203126.8+stretch~1.gbp2ff763 (cli) (built: Dec 8 2018 20:31:26) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2017 Zend Technologies
with Zend OPcache v7.0.33-1+0~20181208203126.8+stretch~1.gbp2ff763, Copyright (c) 1999-2017, by Zend Technologies

Laravel Routing Returns 302 Redirect — November 20, 2018

Laravel Routing Returns 302 Redirect

That was a frustrating few hours. I added a route into my api.php route and every time I visited it it triggered a redirect. I saw nothing in the browser and it was like my controller function wasn’t even being called.

I put the usual dd() and dump() into my function and it wasn’t being called. I even changed the function name so it didn’t exist and thought I’d get an error message, but nothing – still a redirect.

What is going on? I expanded out the call from “Namespace\Class@function” to put in a function () {} and that was being called and ran ok.

Clearly there was something wrong with my class somewhere. The other functions within it worked fine, just this new one didn’t even seem to be there.

Sure enough a bit of Duck-Jitsu and I found this: https://stackoverflow.com/questions/35020477/laravel-unexpected-redirects-302 – answer 3 is where I got my clue.

I looked at my class constructor and I was using the auth middleware to ensure the functions were not used unless authenticated.

public function __construct() {
  $this->middleware(['auth:api']);
}

For my function I wasn’t using any authentication, so of course I was getting a redirect. But because it’s an api call and the expected return in JSON under an XHttpResponse I wasn’t able to properly debug it. I was getting back a HTML page instead.

As a work around all I needed to do was add in an exception for my function:

public function __construct() {
  $this->middleware(['auth:api'], ['except' => [ 'myFunction' ]]);
}

Now all I have to do is go back and sort out the authentication for the function so I don’t need to bypass it.

When is a Question Mark not a ? — August 29, 2018

When is a Question Mark not a ?

That’s a morning of smashing my face on the desk again. I deployed my dev program onto a production system and then started crying as it stopped working as it should.

It seemed that none of my query string parameters were making it through to the controller. I called up some debugging and dumped out my $request and $request->all() etc. and discovered that the parameters although shown in the browser dev window went AWOL between server and controller. On my dev environment it all acted as it should.

So there must be something different. PHP v7.2 on dev and v7.0 or production maybe? No, much simpler than that. None of the Laracasts and Laravel related Googling pulled up any particular clues. It wasn’t until I looked at Nginx and parameters not being passed to PHP that I got a hit.

https://serverfault.com/questions/685525/nginx-php-fpm-query-parameters-wont-be-passed-to-php

The answer was as simple as adding in the $is_args into my Nginx virtual server config.

location / {
  try_files %uri $uri/ /index.php$is_args$query_string;
}

Up until now I guess I’ve been using routing with the parameters as part of the URI. Now I’m using some query string parameters I need to put in the ?, which is the $is_args variable.

So why not a problem in dev? Because I’m not using Nginx, I just use artisan serve to debug my development program.

Laravel and Lagan Web Services – SOAP API — August 17, 2018

Laravel and Lagan Web Services – SOAP API

SOAP is a dirty word to me. But I have a need to interact with our CRM system to import / extract data. My go to platform for most of my PHP work is Laravel. So I looked at interacting with Lagan CRM using SOAP calls from PHP.

I started off accessing the Lagan WSDL pages to see what the capabilities of the API are.

http://[laganserver:8080]/lagan/services/FL?WSDL
http://[laganserver:8080]/lagan/services/FLAuth?WSDL
http://[laganserver:8080]/lagan/schema/FLService.wsdl

Now I can see the self documenting API calls I can make. I just need to create the SOAP envelope to pass data to the service with the call I want to make.

Continue reading

Laravel Debug Bar — August 6, 2018

Laravel Debug Bar

It’s a good job my job title doesn’t include development. Some things I find out seem a long time after I need then and would be useful in the world of development.

My latest discovery is the Laravel debug bar. https://github.com/barryvdh/laravel-debugbar

Using it means not so many dd() or dump() in my code to find out what Laravel sees. It even allows me to see the actual SQL queries being used.

Selection_073
Laravel Debug Bar

In many ways I wish I’d discovered this sooner.

Installation is very simple, just a composer require and then ensure your .env has the debug option enabled and/or debug bar enabled.

APP_DEBUG=true
DEBUGBAR_ENABLED=true

 

Laravel Vue.js and API Routes — July 23, 2018

Laravel Vue.js and API Routes

I ran into a problem where I’ve started to deploy Vue components using the Vue Router from within Laravel. As soon as I enabled the Vue route for /{any} I lost access to the api routes.

routes/web.php

Route::get('/{any}', function () {
  return view('home');
})->name('home')->where('any', '.*');

Auth::routes();

app.js

const routes = [
  {
    path: '/',
    name: 'home',
    component: home
  }, {
  ...
  }, {
    path: '*',
    name: 'notFound',
    component: notFound
  }
]

I took a look at the Laravel RouteServiceProvider.php and noticed that the order of the web and api providers put the web first, so I swapped them around and now my api’s are back in business.

/**
* Define the routes for the application.
*
* @return void
*/
public function map()
{
  $this->mapApiRoutes(); // Needs to be first

  $this->mapWebRoutes();

}

 

 

Building a Debian Development Server — July 13, 2018

Building a Debian Development Server

When I setup a development system there are a few steps I follow to get everything working together.

The aim is to get everything installed to provide php and composer, node, nginx, mysql and Laravel as a base to build on.

Install Debian

I take the latest amd64 version using a network installable iso. This way if I use an older 9.1, 9.2, 9.3 version iso, being a netinst version I’ll end up with the latest in that series as it downloads from the net.

Mostly making a 50GB disk is more than enough, as it’s thin provisioned on a virtual, space isn’t really a concern. When it comes to partitioning I’ve learned to take the easy option and create one partition to mount all filesystems into it.

Capture1

As it’s a development platform I never install a desktop environment. I never need to use any GUI programs on the server. The only options I choose to install are the standard system utilities and the ssh server.

Capture2

Out of personal preference, once up and running I install sudo, zsh, curl and git.

# apt-get install sudo zsh curl git

Then I add my non-root user to the sudo group so I can stop using root and use my regular user account to ssh onto the dev server..

# usermod -aG sudo [user]

Setup OhMyZsh

I like using zsh and the OhMyZsh which is why I installed curl and git. So logon as your non-root user.

$ sh -c "$(curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"

Then I edit the ~/.zshrc file and change the theme to “bureau”.

Network Config

If I’m building a Virtual Box guest that runs on my local PC I’ll setup two interfaces. If it’s a virtual on VMWare I’ll just use the one production interface.

On a local Virtual Box I use one interface as NAT, so it gets a DHCP address like 10.0.2.15 which all outgoing traffic is routed by default. Makes life easier on a corporate network where network authentication is required. Using NAT like this means I don’t need to authenticate my guest as it NAT via my physical hosts authenticated interface.

I then setup second interface so I can connect to what is being served from the guest. This is a “host only” interface and means only my local system can connect to it, but because of the NAT the guest will still have access to the corporate network resources/servers.

This means I end up with two devices usually named enp0s3 (NAT) and enp0s8 (Host Only) on Debian.

Using a Static IP (optional)

I choose to make my system with a static IP. Using the Virtual Box DHCP server on a “host only” interface gives out a 192.168.56.101 address to the first guest, 102 to the second and so on. But you can end up with inconsistent IP’s for your hosts. So making them static is a better option IMO.

Edit /etc/network/interfaces and set you host only adapter to static:

# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).

source /etc/network/interfaces.d/*

# The loopback network interface
auto lo

iface lo inet loopback

# The primary network interface
allow-hotplug enp0s3
iface enp0s3 inet dhcp

allow-hotplug enp0s8
iface enp0s8 inet static
  address 192.168.56.2
  netmask 255.255.255.0

This way My dev system always gets the static IP I chose for it.

$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
  link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  inet 127.0.0.1/8 scope host lo
    valid_lft forever preferred_lft forever
  inet6 ::1/128 scope host 
    valid_lft forever preferred_lft forever
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
  link/ether 08:00:27:61:a6:a8 brd ff:ff:ff:ff:ff:ff
  inet 10.0.2.15/24 brd 10.0.2.255 scope global enp0s3
    valid_lft forever preferred_lft forever
  inet6 fe80::a00:27ff:fe61:a6a8/64 scope link 
    valid_lft forever preferred_lft forever
3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
  link/ether 08:00:27:2b:04:26 brd ff:ff:ff:ff:ff:ff
  inet 192.168.56.2/24 brd 192.168.56.255 scope global enp0s8
    valid_lft forever preferred_lft forever
  inet6 fe80::a00:27ff:fe2b:426/64 scope link 
    valid_lft forever preferred_lft forever

Install PHP

Because we don’t want Apache2 installed you need to install php-fpm which won’t force an install of Apache.

$ sudo apt-get install php-fpm

It will include a load of other php components you need, but no Apache, so you can then choose to move on to Nginx or some other php service.

Add the Laravel php requirements

$ sudo apt-get install php-mbstring php-zip php-xml php-dev php-dom php-ldap libpng-dev make gcc g++

The additional module libpng-dev is required for Laravel to build using NodeJS npm. Without libpng-dev, make, gcc and g++, under your Laravel project folder the call to $ npm i fails with errors like:

> pngquant-bin@4.0.0 postinstall /home/user/myproject/node_modules/pngquant-bin
> node lib/install.js
⚠ The `/home/user/myproject/node_modules/pngquant-bin/vendor/pngquant` binary doesn't seem to work correctly
⚠ pngquant pre-build test failed
ℹ compiling from source
✔ pngquant pre-build test passed successfully
✖ Error: pngquant failed to build, make sure that libpng-dev is installed
at Promise.all.then.arr (/home/user/myproject/node_modules/pngquant-bin/node_modules/bin-build/node_modules/execa/index.js:231:11)
at <anonymous>
at process._tickCallback (internal/process/next_tick.js:188:7)

Install MySQL

As you’ll need a database you’ll want to install MySQL. These days MySQL is installed from the MySQL site by downloading a .deb file which add the Oracle repositories. The version of MySQL in the Debian repositories is MariaDB, a fork of MySQL.

If you go for the Oracle version  you’ll probably need to ensure you use legacy authentication for now.

Include the php drivers as we install the server:

$ sudo apt-get install mysql-server php-mysql

To manage MariaDB using mysql you need to use sudo:

$ sudo mysql -u root
...
MariaDB [(none)]>

Install Composer

Go to your home folder and use the command line install from here: https://getcomposer.org/download/

You’ll end up with a file composer.phar. This is ok if you’re the only one going to use it but I like to put it in /usr/bin as just composer so it is available for everyone.

$ sudo cp ~/composer.phar /usr/bin/composer
$ sudo chmod 755 /usr/bin/composer

Install NodeJS

Install it using a package manager following the steps for Debian

https://nodejs.org/en/download/package-manager/

$ curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -
$ sudo apt-get install -y nodejs

Then the first thing I do is update npm.

$ sudo npm i npm -g

Install Samba

Because not all development takes place on a Linux host this will allow us access to shares for Windows clients.

$ sudo install samba

Edit /etc/samba/smb.conf and make some simple changes.

workgroup=[NETBIOS DOMAIN NAME]

Then find [homes] and in that section change:

read only = no
create mask = 640
directory mask = 750

Create a password entry for your non-root user:

$ sudo smbpasswd -a [user]

Then restart Samba

$ sudo systemctl restart smbd

Then when you browse to the server from windows you should see and have access to your home folder eg. \\192.168.56.2\user

Installing Laravel

I prefer to install Laravel as a project using the Create Project method:

$ composer create-project --prefer-dist laravel/laravel [myproject]

This downloads all of the PHP composer prerequisites and delivers the project.

Once the project is created you can go into the folder [myproject] and check you can compile the assets using Node.

$ cd myproject
$ npm i

This will install all of the NodeJS prerequisites used for building/compiling your assets using the Laravel asset management tools – currently Laravel Mix (Based on Webpack). So with the Node modules installed you should be able to run prod and dev builds:

$ npm run dev
$ npm run prod

These should complete successfully.

You can then run Laravel’s built in development server to serve your project:

$ php artisan serve

But in reality this will fire up a pretty useless server listening on the IP address 127.0.0.1 on port 8000. So it’s only accessible from the development server.

As we’re going to need to access it from our client development machine we need to serve on the actual IP of the server. The easiest way of doing this is to serve it on every IPv4 interface on the server (you probably only have one, so it shouldn’t matter). To do this use:

$ php artisan serve --host=0.0.0.0

and if you want to specify the port you can use:

$ php artisan serve --host=0.0.0.0 --port=8001

Now you can access it from any client pointing your browser at http://192.168.56.2:8001 and begin exploring your Laravel project.

More Laravel

Of course serving a version of your project like this isn’t the only way to go. You should continue into dynamically building your assets using npm run watch and maybe even using tools like browserify to make changes happen at the browser end so you’re not building and refreshing all the time.

I also like to move away from a development web server and setup Nginx to handle serving my Laravel Project.

Further Reading

https://warlord0blog.wordpress.com/2017/03/01/ssh-logon-with-private-key/

https://warlord0blog.wordpress.com/2018/05/16/debian-stretch-ntp-time-sync/

https://warlord0blog.wordpress.com/2017/12/12/php7-0-microsoft-sql-driver-debian-stretch/

https://warlord0blog.wordpress.com/2017/03/01/installing-updating-webmin/