How to upgrade PHP version to 7.2 on Ubuntu 16.10

I decided to upgrade the PHP version in one of my servers from 7.0 to 7.2 to live with the bleeding edge. The process went quite smoothly, except for the last step which I needed to do a bit research.

 

First thing’s first: check your current version

php --version

Also create phpinfo.php file in your /var/www/html directory

<?php phpinfo();

and run the file to be sure that both php CLI and apache version are the same.

 

The Upgrade

You can use a third-party repository to install the latest version of PHP. We’ll use the repository by Ondřej Surý.

First, you need to install the repository.

# install required package so you can add repository
sudo apt-get install software-properties-common

# install the repository and update the repository list
sudo add-apt-repository ppa:ondrej/php

Then, update packages in the system

sudo apt-get update && apt-get upgrade

 

Install PHP 7.2 (or newer version, you can just change the version number in the command)

sudo apt-get install php7.2

 

(optional) install PHP modules, depending on your needs. Note that the version of PHP has to be specified

sudo apt-get install php7.2-dev php7.2-zip php7.2-curl php7.2-gd php7.2-mysql php7.2-mcrypt php7.2-xml libapache2-mod-php7.2

 

Verify PHP version using the command line

$ php --version
PHP 7.2.13-1+ubuntu16.04.1+deb.sury.org+1 (cli) (built: Dec  7 2018 08:07:08) ( NTS )

 

Verify PHP version using phpinfo.php file we created earlier.

!@$^%@$^, the PHP version is still the previous one!!! The reason is that apache is still running with the old PHP version. We will need to change that so the server can run with PHP7.2.

Let’s run the following commands:

# disable old php module
sudo a2dismod php7.0

# enable new php module
sudo a2enmod php7.2

# restart the server
sudo service apache2 restart

Verify the PHP version again, and it should be updated to our new version.

PHP version 7.2.13

If you want to upgrade to a different version of PHP, just change the version number while installing, and don’t forget to disable the old PHP module and enable the new one for Apache.

I hope this helps you with your work, and have fun upgrading 😀

React logo

React 16.6 new features: contextType, lazy, memo

In Oct 24, 2018, React 16.6.0 was published to npm. It brings a lot of exciting new features, including contextType, React.lazy() and React.memo(). We will discuss in depths of what they are and how will they change your React ecosystem.

In this blog post, I am going to assume that you already have certain experience with React, and have been working with React for a little while (mainly for understanding the tremendous advantages that the new features will bring us.

contextType

In React 16.3, Facebook released context API officially, shaking the foundation of state management systems like redux, mobx. In React 16.6, context API is further improved by introducing static contextType.

const SampleContext = React.createContext();


class WithContextAPIComponent extends React.Component {
  render() {
    return (
      <SampleContext.Consumer>
        {(value) => (<div>value.name</div>)}
      </SampleContext.Consumer>
    );
  }
}


class WithContextTypeComponent extends React.Component {
  static contextType = SampleContext;
  
  render() {
    const value = this.context;
    
    return (<div>value.name</div>);
  }
}


// usage
<SampleContext.Provider value={{ name: 'Tuan Nguyen' }}>
  <WithContextAPIComponent />
  <WithContextTypeComponent />
</SampleContext.Provider>

With the sample above, we can see that with contextType, we bound the context value to the component itself, which simplifies one layer of nested component to be rendered. This suddenly looks like it is so much similar to how we use redux store!!!

 

React.memo()

This is very simple. It enables the same functionality of React.PureComponent for functional components.

const MyComponent = React.memo(function MyComponent(props) {
  /* only rerenders if props change */
});

Previously functional components will re-render every time its props change, regardless of value.

With React.memo(), now functional components will shallowly check whether props values have changed, and decide to re-render.

React.lazy()

In my opinion, this is the most outstanding feature that React 16.6 offers.

Short description: it allows React components to only be downloaded from server on demand.

import React, {lazy, Suspense} from 'react';
const OtherComponent = lazy(() => import('./OtherComponent'));

function MyComponent() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <OtherComponent />
    </Suspense>
  );
}

In the example, MyComponent will download OtherComponent only when it is needed.

This is very useful in tabular structure, where most users do not browse every tab content.

 

For more information, let’s check out the changelog at https://reactjs.org/blog/2018/10/23/react-v-16-6.html

Write automated script with Tampermonkey and Webpack

Recently I was pulled into an old web-based game called Ghost Trapper. The gist of it is, after a period of time, I can click on a button to trap a ghost, then a count down appears and I have to wait for the count down to stop until I can hunt ghosts again.

Then it hit me, why don’t I automate the process so that I don’t have to spend so much time to play anymore.

Here’s a screenshot of the game.

Ghost trapper screen image

Note the top left count down. Once it reaches 0, I can click that button again and continue hunting ghosts.

I look around for a solution for automating the process. There are quite a few options:

  • Python’s scrapy
  • Phantom.js or Casper.js
  • Puppeteer
  • Tampermonkey (Google Chrome only)

I have some experience in Scrapy, Phantom.js; so I was thinking, why not utilize what I have already known?

… Or I can jump into new things and learn how to do it.

 

I decided to go with the second option, and I chose Tampermonkey to do the work.

 

So I quickly wrote a small script to check if the button is active, and if so, click on it.

setTimeout(() => {
  if (!$('#huntBtn').hasClass('disabled')) {
    $('#huntBtn').trigger('click');
  }
}, 3000);

Simple, isn’t it?!

The problem is, I would like to have the script runs on multiple machines, and I want to synchonize the code in all machines, so if I update the code I’ll just need to do it once.

I ended up with the following structure:

  • A github project to host the code
  • Tampermonkey’s ability to refer to external javascript resources.

My Tampermonkey script

// ==UserScript==
// @name         ghost-trapper
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  Ghost Trapper auto
// @author       lightbringer
// @noframes
// @require      https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js
// @require      file:///Z:/nodejs/ghost-trapper/ghost-trapper.js
// @match        http://www.ghost-trappers.com/fb/*
// @grant        GM_setValue
// @grant        GM_getValue
// ==/UserScript==

My ghost-trapper.js

class GhostTrapper {
  constructor() {
    // do stuff
  }
  
  hunt() {
    if (!$('#huntBtn').hasClass('disabled')) { 
      $('#huntBtn').trigger('click'); 
    }
  }
  
  run() {
    setTimeout(this.hunt, 3000);
  }
}


var gt = new GhostTrapper();
gt.run();

 

Looking good, however, the script requires 2 files, one from jquery CDN. one from my local machine. And the speed is not very nice (took me a noticeable time before the hunt click happened).

I thought, why can’t I combine them into 1 file? I have experience in Webpack, so let’s try it out.

 

First I installed necessary packages

npm i --save jquery
npm i --save-dev webpack webpack-cli babel-core babel-loader babel-preset-env

Then I created webpack config file

// webpack.config.js

const path = require('path');

module.exports = {
  entry: './src/main.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'ghost-trapper.bundle.js'
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /(node_modules|bower_components)/,
        use: {
          loader: "babel-loader",
        },
      },
    ],
  },
};

Then I create a main file for webpack to point to.

// src/main.js 
import $ from 'jquery'; 
import GhostTrapper from './GhostTrapper'; 

const gt = new GhostTrapper(); 
gt.run();

 

After all this, I compile webpack config. And voilà, the bundle is ready for me to include into tampermonkey, and it runs exactly what I wanted.

From then on, I added multiple features to my automation tool. The ease of webpack’s watch mode really helps me during development, as I just need to refresh the page and the new code is already deployed.