Monday, 7 November 2022

PHP Convert Hex String to String

How to decode Hex String to String?

Ex: Decode Hex String to get JWT token when integrating Apple ID login


Hex string is a data type commonly used for transmission over the internet in the lower network layers. In some cases PHP will need to manipulate this data type directly. To handle them, PHP provides us with the "pack" function to manipulate Hex and binary string data.


$stringHexData = "65794a68624763694f694a49557a49314e694973496e523563434936496b705856434a392e65794a7063334d694f694a6f64485277637a6f764c3246776347786c61575175595842776247557559323974496977695958566b496a6f69593239744c6e4e68625842735a533568634841694c434a6c654841694f6a45324d5459354f4455794e6a4973496d6c68644349364d5459784e4449314d444d334d69776963335669496a6f694d4441774e7a677a4c6d4e6b5a6a45354d47526b4d544130595452685a6a42694e6d49774e6a63784d3249344d4455304d6a52694c6a45304d5451694c434a6a58326868633267694f694a7852557035546d7473556d4a5a626c46565679316b646d6774536b7452496977695a573168615777694f694a7a59573177624756415a3231686157777559323974496977695a57316861577866646d567961575a705a5751694f694a30636e566c4969776959585630614639306157316c496a6f784e6a45324f5441774d7a63794c434a756232356a5a56397a6458427762334a305a5751694f6e527964575573496e4a6c5957786664584e6c636c397a6447463064584d694f6a4a392e764b6c394873303057587463426851796f47326742766a744375394d5878787471674e46777854772d5034";

$stringData = pack("H*",$stringHexData);

echo $stringData;

Result (JWT String): 



In addition, the "pack" function also supports other data types. 

possible values of format are:
a – string which is NUL-padded
A – string which is SPACE-padded
h – low nibble first Hex string
H – high nibble first Hex string
c – signed character
C – unsigned character
s – signed short (16 bit, machine byte order)
S – unsigned short ( 16 bit, machine byte order)
n – unsigned short ( 16 bit, big endian byte order)
v – unsigned short ( 16 bit, little endian byte order)
i – signed integer (machine dependent byte order and size)
I – unsigned integer (machine dependent byte order and size)
l – signed long ( 32 bit, machine byte order)
L – unsigned long ( 32 bit, machine byte order)
N – unsigned long ( 32 bit, big endian byte order)
V – unsigned long ( 32 bit, little endian byte order)
f – float (machine dependent representation and size)
d – double (machine dependent representation and size)
x – NUL byte
X – Back up one byte
Z – string which is NUL-padded
@ – NUL-fill to absolute position

Saturday, 5 November 2022

Android - Replace OnLifecycleEvent is deprecated with DefaultLifecycleObserver or LifecycleEventObserver

As of androidx.lifecycle version 2.4.0, OnLifecycleEvent is deprecated. Instead Use DefaultLifecycleObserver or LifecycleEventObserver is recommended to use instead. Many android applications that use OnLifecycleEvent such as when integrating Admob Open Ads will receive a warning.

For example, the following code will be warned by Android Studio OnLifecycleEvent is deprecated:

     * LifecycleObserver methods
    public void onStart() {
        Log.d(LOG_TAG, "onStart");
To replace OnLifecycleEvent, follow these instructions:

First: In build.gradle, please include the LifecycleObserver libraries:

apply plugin: ''

dependencies {

   implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
   implementation "androidx.lifecycle:lifecycle-runtime:2.5.1"
   annotationProcessor "androidx.lifecycle:lifecycle-compiler:2.2.0"

Then choose one of the following two alternatives:

Method 1: replace OnLifecycleEvent with DefaultLifecycleObserver

import androidx.lifecycle.DefaultLifecycleObserver;

public class MyApplication extends Application implements DefaultLifecycleObserver {
    public void onCreate() {
	// Register DefaultLifecycleObserver 

    /*Replace for OnLifecycleEvent onStart Event */
    public void onStart(@NonNull LifecycleOwner owner) {
	// Perform actions every time the app is reopened

Method 2: replace OnLifecycleEvent with LifecycleEventObserver

public class MyApplication extends Application implements LifecycleObserver
  public void onCreate() {
    // Register LifecycleObserver

  /*Replace for OnLifecycleEvent onStart Event */
  protected void onMoveToForeground() {
    // Perform actions every time the app is reopened (moves to foreground)
    // appOpenAdManager.showAdIfAvailable(currentActivity);

Done !

If you have any difficulties, or have any questions, please leave a comment below the article. We will deal with them together. Thanks

Friday, 21 October 2022

Flutter Dart Error: Can't load Kernel binary - Invalid kernel binary

During working with Flutter, Error "Can't load Kernel binary" may arise unexpectedly after we make some changes to the application. This error is often confusing for developers because it often does not specify a clear cause. Even if you haven't done anything wrong, mistakes can still appear spontaneously. With luck, cleaning the project can fix this problem, but in many cases it doesn't work.

Example of an error message:

[ERROR:flutter/shell/common/] Dart Error: Can't load Kernel binary: Invalid kernel binary: Indicated size is invalid.
   .../runtime/] Could not create root isolate
   ./android/] Could not launch engine in configuration.


Android Studio's compiler sometimes doesn't work as expected, so the process of linking libraries to compile Dart source code may encounter errors that distort the project's configuration paths. This results in errors during or after compilation with cryptic errors, even errors reported that seem absurd, unrelated to the problem. (It appears to be similar to the bug in Android Studio's Dart code suggestion function. In many cases Android Studio suggests inserting const or required keywords but inserts these keywords in the wrong place. which it is suggested.).
Once errors of this type arise, it is often cached in the project, so many times we try to find ways to not handle the error, but sometimes it suddenly disappears and cannot be re-appeared.

"Dart Error: Can't load Kernel binary: Invalid kernel binary: Indicated size is invalid."

Solve it

Please try the following steps one by one until the problem is resolved

Step 1: Clear project cache
Completely close the application in the virtual machine.
In the main project directory, run the command: "flutter clean"
Then run "flutter pub get" again to update the libraries. 
Rebuild the project to see if the error has been resolved, You can also try to change a little bit in the application's code to make sure the application has been rebuilt and not loaded from the cache. If the problem is not resolved, try step 2

Step 2: Clear Flutter SDK Cache
Go and delete all files in the cache folder of Flutter SDK.
As required when installing, the Flutter SDK is usually installed in the C drive. For example: C:/flutter
You can also easily find the path to the Flutter SDK in the ".flutter-plugins" file inside your project.
After clearing the cache, run the "flutter doctor" command again to let flutter update the libraries (you can run "flutter doctor" from anywhere).
Re-open Project to see if the problem has been resolved. If not, continue with step 3.

Step 3: Rollback of previous project changes
Try reversing some of the last changes you made to the project's source code. (Remember to save those changes because you can still use them normally if they're not wrong.) Reversing changes, creating changes in the project's source code can help clear caches and miscompiled configuration fragments.
If the error is still not resolved when you have reversed the small segments then try some higher level change in the file "main.dart"

Note: In the process of fixing errors, you should not use "hot restart"

If there is anything more to share in this situation, please leave information in the comment section so we can discuss.

Tuesday, 30 August 2022

MariaDB/MySQL - Fix error "Unknown/unsupported storage engine: InnoDB" by using recover mode

Although the InnoDB storage engine has mechanisms to preserve data, problems such as power failure or sudden restart can still cause errors in MySQL/MariaDB data. These errors can make the system unable to boot, unable to restore the normal data state. Some of the error messages we often encounter are listed below.

[Note] InnoDB: Starting shutdown...
[ERROR] InnoDB: Database was not shut down normally!
[ERROR] Plugin 'InnoDB' init function returned error.
[ERROR] Plugin 'InnoDB' registration as a STORAGE ENGINE failed.
[Note] Plugin 'FEEDBACK' is disabled.
[ERROR] InnoDB: Starting crash recovery from checkpoint LSN=1637690
[ERROR] Unknown/unsupported storage engine: InnoDB
[ERROR] Aborting

Note: Some crashes are caused by other causes but also return the error message "Unknown/unsupported storage engine: InnoDB". In that case, there will be more detailed information in the MySQL log to help you find the cause and handle it. As for the cases where the service can't tell why InnoDB is unsupported or unrecoverable, most of the time, data errors are caused. You can handle that case according to the instructions in this article.

To use this mode is very simple. You just need to specify the value innodb_force_recovery in the installation file of MySQL or MariaDB. Then restart the service. MySQL will restart and try to use recovery mode to recover the corrupted data.

innodb_force_recovery = 1

MySQL has a total of 6 recovery modes in ascending severity. You often choose to get the most suitable mode for your system. Please try again with a higher level if the error is not resolved.

Lets the server run even if it detects a corrupt page. Tries to make SELECT * FROM tbl_name jump over corrupt index records and pages, which helps in dumping tables.

Prevents the master thread and any purge threads from running. If an unexpected exit would occur during the purge operation, this recovery value prevents it.

Does not run transaction rollbacks after crash recovery.

Prevents insert buffer merge operations. If they would cause a crash, does not do them. Does not calculate table statistics. This value can permanently corrupt data files. After using this value, be prepared to drop and recreate all secondary indexes. Sets InnoDB to read-only.

Does not look at undo logs when starting the database: InnoDB treats even incomplete transactions as committed. This value can permanently corrupt data files. Sets InnoDB to read-only.

Does not do the redo log roll-forward in connection with recovery. This value can permanently corrupt data files. Leaves database pages in an obsolete state, which in turn may introduce more corruption into B-trees and other database structures. Sets InnoDB to read-only.

Finally, after troubleshooting, restore the "innodb_force_recovery" configuration to level 0 and then restart the database service to keep the system working properly.

Also note that this is only a workaround, it may also fail if the data is badly corrupted. Our advice remains that every database system should always have a mechanism to automatically back up data.

Sunday, 21 August 2022

[Flutter] Async Function vs Normal Function in Dart, How do they work?

 "Synchronous", "asynchronous", "await" and "asynchronous functions" are very confusing concepts when used in Flutter. For ease of explanation, in this article we will analyze two types of Flutter functions: Normal Function and Async Function. We will learn how these two types of functions work.

Ficture 1: Flutter/Dart async work flow

Normal Function and Async Function

The Dart language that Flutter uses inherits many features from Javascript. Dart's handling of synchronous and asynchronous jobs is also very similar to Javascript. There are two types of functions in the Dart language:

* Normal Function:

A function in Dart is declared as follows:

String doSomthing(){
    print('This is a normal Function');
    // do somthing
    return 'Done!';

* Async Function:

Async functions are functions declared with the async keyword at the end. 

String getApiContent() async{
    print('Async function loading api from Server');
    final response = await http.get(Uri.parse(''));
    return response.body;
The difference of Async functions from normal functions is that in an Async function you will be able to use the await keyword to wait for another function to finish executing. Also, an Async doesn't return an immediate result, it just returns a Future.

Dart is an asynchronous language

By default, Dart always tries to process everything asynchronously whether it is an async function or a normal function. Let's analyze the example depicted in Figure 1.

Like other programming languages, DArt will also process the source code line by line from top to bottom. Even when encountering an Async function it continues to deal with the same logic. That's why in the example we see line 1 and line 2 in asyn function callApi still being executed. "Async" appears only when an actual async event occurs (http.get).

Inside an Async function when encountering a "real" async event (a predefined async event by Dart, not a self-created async function) there are 2 options.

Case 1: you can use the await keyword to wait until the async event completes and return the result. The current async function will break at that location. You did not read it wrong, Exactly, the async function will be interrupted at that point, not a new thread or process is initialized to run in the background at this time to continue the async task we are expecting. (You can use additional tools like Charles to verify this.) Of course Dart has kept in mind that there is an Async event still pending. Next Dart will return to the main program to continue to execute the next lines of code. That's why we see the sleep function being executed immediately followed by lines 3, 4, 5 being executed. After the main program has completed, Dart returns to continue processing asynchronous events and the next line of code in the async function.

Case 2: if you don't use await keyword before async event. Just like the case of 1 Dart will remember the pending asynchronous event, but next Dart will continue to execute the next code in the current async function as if nothing happened.

import 'package:http/http.dart' as http;
import 'dart:io';

void main(){	
  print('Line 1 - done !');
  var apiResult = callApi();
  sleep(Duration(seconds: 15)); // Test to monitor async task
  print('Line 3 - done !');
  print('Line 5 - done !');

Future callApi() async{
  print('Line 2 - Async Function callApi called');
  print('==>A: Line 2 - Line 2 function callApi');
  final response = await http.get(Uri.parse(''));
  print('==>A: Line 3 - call api done !');
  print('==>A: Line 4 - done !');
  return 'Done !';

void normalFunction1(){
  print('Line 4 - This is normalFunction1');
void normalFunction2(){
  print('==>A: Line 1 - This is normalFunction2');


I/flutter (21546): Line 1 - done !
I/flutter (21546): Line 2 - Async Function callApi called
I/flutter (21546): ==>A: Line 1 - This is normalFunction2
I/flutter (21546): ==>A: Line 2 - Line 2 function callApi
I/flutter (21546): Line 3 - done !
I/flutter (21546): Line 4 - This is normalFunction1
I/flutter (21546): Line 5 - done !
I/flutter (21546): ==>A: Line 3 - call api done !
I/flutter (21546): ==>A: Line 4 - done !

Dart is a single-threaded programming language

The reason Dart has to handle such complex asynchronous events is because it was designed to be a single-threaded language. By default our entire Flutter application runs on a single Dart thread. You will also still be able to create additional threads to actively handle parallel or background tasks, but then you will have to deal with the problems that arise.


When it encounters an async event, Dart will always push it to the bottom to wait for it to be processed. If there is await before the async call, all code that follows will also be pushed to the bottom to wait with it. Otherwise the next lines of code will still be treated as if nothing happened. Understanding how Dart's async works will help you optimize your application.

Friday, 29 July 2022

[Flutter] Fix install error "cmdline-tools component is missing" and "Android license status"

Flutter on windows

Command line tools are very useful during android app development with Flutter. In some cases you may have difficulty installing it due to version incompatibility or conflicts with other software. After installing cmdline-tools you can continue to confirm the Android license.

Sample Flutter doctor analytic info:

C:\Users>flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[√] Flutter (Channel stable, 3.0.5, on Microsoft Windows [Version 10.0.19043.1826], locale en-US)
[!] Android toolchain - develop for Android devices (Android SDK version 33.0.0)
    X cmdline-tools component is missing
      Run `path/to/sdkmanager --install "cmdline-tools;latest"`
      See for more details.
    X Android license status unknown.
      Run `flutter doctor --android-licenses` to accept the SDK licenses.
      See for more details.
[√] Chrome - develop for the web
[X] Visual Studio - develop for Windows
    X Visual Studio not installed; this is necessary for Windows development.
      Download at
      Please install the "Desktop development with C++" workload, including all of its default components
[√] Android Studio (version 2021.2)
[√] VS Code (version 1.69.2)
[√] Connected device (3 available)
[√] HTTP Host Availability
! Doctor found issues in 2 categories.

As suggested, you just need to run the command: Run `path/to/sdkmanager --install "cmdline-tools;latest"`. But there might be an error: Exception in thread "main" java.lang.NoClassDefFoundError: javax/xml/bind/annotation/XmlSchema. In this case we can fix it by installing cmdline-tools through Android Studio. This method is always applicable and very easy to do.

Step 1: In the Android Studio software, you click on the menu Tools >> SDK Manager

Step 2: In the SDK Manager setting screen, select the "SDK Tools" tab. Then tick "Android SDK Command-line Tools (lastest)". Finally click "Apply" to start the installation.

Step 3: After installing "Command-line Tools" you can open a command line window to continue to confirm "Android licenses"

flutter doctor --android-licenses

Done ! Check Flutter doctor to make sure everything is fully installed. Good luck.

Tuesday, 26 July 2022

[Laravel] How to find out which Class and File are behind a Facade

Facades in Laravel allow us to call libraries very conveniently. However, developers who are new to a project will find it difficult to investigate errors because Laravel Error Handling does not specify which class caused the error. In particular, the problem is very common with Facades that have many services  available. Ex: DB, Image, Auth, Cache, Mail...

Laravel Facade Flow

* Quick debug:

To find out the PHP class behind a Facade that you don't know where it is, you can debug it with the following code:
$behindClass = get_class(\<<Facade>>::getFacadeRoot());
$classReflector = new \ReflectionClass($behindClass);
dd($behindClass, $classReflector->getFileName(), $classReflector);
$behindClass = get_class(\Mail::getFacadeRoot());
$classReflector = new \ReflectionClass($behindClass);
dd($behindClass, $classReflector->getFileName(), $classReflector);

* Understand how the Facade is loaded by Laravel:

To find the underlying class behind a Laravel Facade without debugging you need to understand how a Facade is installed and loaded into Laravel.
Facade looks magical, but it's actually based on PHP's built-in class_alias feature. You can see in the project's config file (/config/app.php) there is a block to declare the Facade class alias.
'aliases' => [
  'Lang' => Illuminate\Support\Facades\Lang::class,
  'Log' => Illuminate\Support\Facades\Log::class,
  'Mail' => Illuminate\Support\Facades\Mail::class,
If you open the class Illuminate\Support\Facades\Mail you will see that the class is almost completely empty. It has very little source code and doesn't really handle any features. In this file, the most special thing we see is the getFacadeAccessor() function and this function does not process anything but just returns a simple string like "mailer". This function is present in all Facades.
protected static function getFacadeAccessor()
         return 'mailer';
It looks magical, but it's not really here. Illuminate\Support\Facades\Mail inherits another class, Illuminate\Support\Facades\Facade::class . In this superclass Laravel will call getFacadeAccessor() to get the name of the actual service that has been configured by laravel for this facade. The example here is 'mailer'. Laravel will then call the 'mailer' service to return the Facade call - app('mailer').
You may be wondering that until now we still do not know where the 'mailer' service is located and how it is declared in Laravel.
Normally, every Laravel service needs to be declared through a Provider and then be available anywhere. Facades are treated the same way. Usually when you install a service pack from outside you will see in the source code of that service pack in addition to the Class Facade there will be a Class Provider to declare the service with Laravel. This means that once we have found information about Facade's extension in config/main.php, we can next look for Class Provider in that extension's source code to see the exact services that have been provided. How is it declared and what files it leads to.
class MailServiceProvider extends ServiceProvider implements DeferrableProvider
    public function register()
    protected function registerIlluminateMailer()
        $this->app->singleton('mailer', function ($app) {
            $config = $app->make('config')->get('mail');
Usually the Providers will be installed automatically when we add the extension package to the project. In addition, Providers can also be manually declared in "config/app.php". There are some services that are core of Laravel, so by default they are declared when laravel starts. For example, with the 'mailer' service we just learned about. For core services, the Facade location and the service source code may be different. As with most package that you install from a third party, the Facade source code, Facade Provider, and Facade-related files are all in the same place in Vendors.

* Note:

we can read the source code in the "vendor" to understand and find a way to fix the error faster, but it is absolutely not recommended to edit the source code directly in the "vendor".

Saturday, 28 May 2022

[Windows 7] Your connection is not private NET::ERR_CERT_AUTHORITY_INVALID for all HTTPS sites

Recently, Windows 7 users reported an error that they could not access the websites "Your connection is not private", "NET::ERR_CERT_AUTHORITY_INVALID". This error is encountered in all browsers on the machine. And it is encountered only when accessing websites with https. In other cases, the website displays a blank page because the static content files cannot be loaded. This error is encountered because the customer's Windows 7 operating system is not fully updated with security patches.

SSL certificate error on all browsers, for all HTTPS sites


To fix this, If you are using windows 7, please install security update KB3004394 from Microsoft.
You can download the KB3004394 package from the official Microsoft website using the following link:

To install the update successfully, Windows must have the Windows Update feature enabled.

After installing the update above, please clear your browser's browsing history data and restart your computer. HTTPS sites can now be accessed normally.
In addition, you should also install all the latest updates for your windows 7 operating system through the Windows Update feature. This will help keep your computer safe and less prone to problems.

Done !

Thursday, 12 May 2022

[Solved] SSH and Gitlab negotiate error "no matching host key type found"

When using new Linux operating systems like Ubuntu 22.04 you may have trouble with SSH when you want to connect to old Linux servers.

Unable to negotiate with ***.***.***.*** port 22: no matching host key type found. Their offer: ssh-rsa,ssh-dss

This error can be encountered when you directly access an old server via SSH. Or when you use Git, SVN, or any other software that uses the SSH protocol.


To be able to make an ssh connection, the Server and the client need to negotiate a secure connection encryption method. That is to find an encryption method that both the server and the client support. OpenSSH in older OS versions like Centos 6 only supports the old encryption standards ssh-rsa and ssh-dss. These 2 encryption standards are outdated and potentially dangerous. Therefore, the new version of OpenSSH disables these encryptions by default. Newer encryption commonly used is ssh-ed25519, ecdsa-sha2 ...


To solve this error, you need to configure ssh on the new server to accept the old encryption standards as ssh-rsa or ssh-dss (just 1 is enough). We suggest 2 solutions to do just that.

Solution 1:

Enable dss or rsa encryption for ssh on your new server.

To do so open the file "~/.ssh/config"

vi ~/.ssh/config

Then add the following content to the file (change ssh-rsa to ssh-dss if your old server only support it)

Host *
HostkeyAlgorithms +ssh-rsa
PubkeyAcceptedKeyTypes +ssh-rsa

Done ! Now you can connect ssh to old servers via terminal normally. However, if you are using Git over ssh with a privateKey file, this will not work (to solve see solution below).

Tip: you can also restrict opening this encryption method only to a certain ip by substituting that ip in the "Host: oldserverIP" section. This will make your server more secure.

Solution 2:

Enable dss or rsa encryption only when a connection is needed by adding a parameter to the ssh connect statement.




ssh -oHostKeyAlgorithms=+ssh-rsa -oPubkeyAcceptedAlgorithms=+ssh-rsa

Done !

Fix negotiate error for Git/Gitlab via ssh privateKey file

With git or edit the config file as follows

vi yourProjectPath/.git/config

        repositoryformatversion = 0
        filemode = true
        bare = false
        logallrefupdates = true
sshCommand =  ssh -oHostKeyAlgorithms=+ssh-rsa -oPubkeyAcceptedAlgorithms=+ssh-rsa  -oIdentitiesOnly=yes -i /yourPath/privateKeyFile.ppk -F /dev/null
Done ! Your Git can now connect to the server normally and it automatically uses the privateKey file to log in instead of having to enter a password.

Friday, 15 April 2022

Laravel 9 Error: Undefined constant Illuminate\Http\Request::HEADER_X_FORWARDED_ALL

Solve the error when upgrading the system to laravel 9 or 10. "Undefined constant Illuminate\Http\Request::HEADER_X_FORWARDED_ALL"


As of Laravel 9, the framework switched to using a built-in middleware to handle proxy queries instead of Fideloper\Proxy\TrustProxies. So when upgrading from lower versions like laravel 5.8, laravel 8 to laravel 9 we also need to edit to replace this middleware. If you don't make changes you will get an error when you run "composer update" and you won't be able to access the website

Solve the problem:

Step 1: Edit your current TrustProxies Middleware (app/Http/Middleware/TrustProxies.php)

Step 2: Update middleware according to the following example

namespace App\Http\Middleware;
use Illuminate\Http\Middleware\TrustProxies as Middleware;
use Illuminate\Http\Request;
class TrustProxies extends Middleware
     * The trusted proxies for this application.
     * @var array<int, string>|string|null
    protected $proxies;
     * The headers that should be used to detect proxies.
     * @var int
    // Before...
    // protected $headers = Request::HEADER_X_FORWARDED_ALL;
    // After...
    protected $headers =
        Request::HEADER_X_FORWARDED_FOR |
        Request::HEADER_X_FORWARDED_HOST |
        Request::HEADER_X_FORWARDED_PORT |

Step 3: Remove Fideloper TrustProxies from composer file

composer remove fideloper/proxy

Step 4: Done ! run "composer update" to complete update