Youtube channel !

Be sure to visit my youtube channel

Friday, February 07, 2020

Docker, XDebug and VSCODE in Ubuntu

Installing XDebug under VSCode is not a very easy task, especially under the Docker environment. Here is my way of doing it. References: Docker for web developers course.



You can learn more about Docker for web development in the following course.

Here is the sample Dockerfile for creating an Apache/PHP host, enabling and then configuring xdebug:

FROM php:7.4.2-apache
RUN pecl install xdebug && docker-php-ext-enable xdebug \
# not yet in linux: xdebug.remote_host = host.docker.internal \n\
&& echo "\n\
xdebug.remote_host = 172.19.0.1 \n\
xdebug.default_enable = 1 \n\
xdebug.remote_autostart = 1 \n\
xdebug.remote_connect_back = 0 \n\
xdebug.remote_enable = 1 \n\
xdebug.remote_handler = "dbgp" \n\
xdebug.remote_port = 9000 \n\
xdebug.remote_log = /var/www/html/xdebug.log \n\
" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini

here is the service allowing port 8000 to be accesed outside:
docker-compose.yaml
version: "3.7"
services:
apache_with_php:
build: .
volumes:
- ./:/var/www/html/
ports:
- "8000:80"

and here is the configuration for debug (F5) inside of VSCode:
.vscode/launch.json
{
"version": "0.2.0",
"configurations": [

{
"name": "Listen for XDebug",
"type": "php",
"request": "launch",
"port": 9000,
"pathMappings": {
"/var/www/html/": "${workspaceFolder}"
},
}
]
}

Don't forget the most important thing, to enable reverse port 9000 on the host running xdebug, in order for the container to be able to connect to this port:

sudo ufw allow in from 172.19.0.0/16 to any port 9000 comment xdebug

Then we just build and run the container
/usr/bin/docker-compose up

For debugging purposes we can enter inside the container using bash shell:
docker exec -it php-debug_apache_with_php_1 /bin/bash
in the xdebug.log file we can find useful information for the initialization of xdebug: cat xdebug.log

then just browse: http://127.0.0.1:8000/index.php, place some breakpoint inside the index.php file, press F5 and refresh the web page to see the debugger (xdebug) running.

Congratulations and enjoy the course!

Wednesday, February 05, 2020

How to restore a deleted Ubuntu kernel / python

Rule NR.1 always keep at least 2 working kernels installed on your system!
For more information on the Ubuntu server administration, I would recommend taking the Practical Ubuntu Linux Server for beginners course.



This is a very painful exercise, but if you are careful during the steps it will be beneficial.
First, boot into liveCD or liveUSB and ensure you have networking.
mount the partitions:
here /dev/sda2 is the partition of my hard drive, where the kernel is broken. 

you can check yours by typing: lsblk
sudo mount /dev/sda2 /mnt 
sudo mount --bind /run /mnt/run
sudo mount /udev /mnt/udev
sudo mount --bind /dev /mnt/dev
sudo mount --bind /proc /mnt/proc
sudo mount --bind /sys /mnt/sys

enter the hard drive environment:
sudo chroot /mnt

mount -t devpts none /dev/pts
from now on you are working back as if you have booted from your hard drive.

Then wait to finish: apt update && apt dist-upgrade

Note:

if in this step you experience problems such as:

dpkg: error processing archive /var/cache/apt/archives/gcc-10-base_10.2.0-13ubuntu1_i386.deb (--unpack):
 trying to overwrite shared '/usr/share/doc/gcc-10-base/changelog.Debian.gz', which is different from other instances of package gcc-10-base:i386

just install the package with --force-overwrite from the cache:

sudo dpkg -i --force-overwrite /var/cache/apt/archives/gcc-10-base_10.2.0-13ubuntu1_i386.deb
and re-run: sudo apt dist-upgrade to complete the installation of the packages

(repeat this for every error until: apt dist-upgrade completes, it may take you some time while installing all the dependent packages resulting in errors)

If you are just missing the old system i.e. having deleted python libraries, do sudo apt install ubuntu-desktop , exit the chrooted shell, and reboot the computer.

Now to the kernel restoration process:

We will skip the grub loader update which may prevent some of the next installations or removals of packages:

sudo mv /etc/kernel/postrm.d/zz-update-grub /etc/kernel/postrm.d/zz-update-grub.bad
Check what version of the kernel are you running with uname -r
then type dpkg -l | grep linux-image
and find at least one kernel starting with ii -> which means it is correctly installed on your system and can be used to boot from later.
- if there is none kernel installed, go ahead and try to install some:
apt install linux-headers-generic
apt install linux-image-generic
- if you experience problems while installing this kernel, install a custom kernel of your preference. The trick is to have the kernel with ii in front!
- if you have problematic kernels(those marked with rH (half-installed) or other flags such as rc (removed)) you can remove them first with apt purge kernel_version...
restore the grub loader updates:
sudo mv /etc/kernel/postrm.d/zz-update-grub.bad /etc/kernel/postrm.d/zz-update-grub


lastly, get your new kernel settings inside of the grub loader:
update-grub

Then exit the chrooted shell and reboot.

One last thing, since we are using USB/LiveCD update-grub could detect also the OS inside those devices, and bloat the whole boot menu.
So after rebooting just re-create the grub configuration with: sudo grub-mkconfig -o /boot/grub/grub.cfg

Congratulations and happy learning!

Sunday, January 26, 2020

JavaScript form validation with promises and exceptions handling

It is good to know the basics of handling web forms. The client entered data usually requires initial validation handled by the JavaScript interpreter of the browser. Here is how to approach the aspects of validating and sending data, as well as parsing the returned server response with the help of JavaScript built-in features such as promises and exceptions. More on them you can learn in this JavaScript course.


<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <style>
    #info {
      opacity: 1;
      transition: opacity 5s;
    }

    #info.hidden {
      opacity: 0;
    }
  </style>
</head>

<body>

  <form id="user-input">
    <div class="form-control">
      <label for="username">Username</label>
      <input type="text" id="username" />
    </div>
    <div class="form-control">
      <label for="password">Password</label>
      <input type="password" id="password" />
    </div>
    <button type="submit" id="submit" disabled>Create User</button>
  </form>

  <span id="info"></span>


<script>
  const REQUIRED = 'REQUIRED';
  const MIN_LENGTH = 'MIN_LENGTH';

  function isValid(value, attr, validatorValue) {
    if (attr === REQUIRED) { return value.trim().length > 0; }
    if (attr === MIN_LENGTH) { return value.trim().length > validatorValue; }
  }

  function createUser(userName, userPassword) {
    if (!isValid(userName, REQUIRED) || !isValid(userPassword, MIN_LENGTH, 5)) {
      throw new Error('Wrong username or password.'); // client-side check
    }
    // return the server-side check promise
    return new Promise(function (resolve, reject) {
      // db checking logic
      is_created = true;
      if (is_created) {
        resolve(
          {
            userName: userName,
            createdAt: +new Date,
            message: 'successfully created user'
          }
        )
      }
      else {
        reject(
          {
            message: 'not valid user or password'
          }
        );
      }
    });
  }

  function displayInfo(info) {
    const info_el = document.querySelector('#info');
    info_el.innerHTML = JSON.stringify(info);
    info_el.classList.toggle('hidden');
  }

  function signupHandler(event) {
    event.preventDefault();
    try {
      createUser(enteredUsername.value, enteredPassword.value)
        .then( // return from the server-side promise
          (info) => { displayInfo(info); },
          (error) => { displayInfo(error); }
        );
    } catch (err) { displayInfo(err.message); } // return from client-side error (throw)
    // .message is auto generated from the throw error object
  }

  const form = document.querySelector('#user-input');
  form.addEventListener('submit', signupHandler);

  // access the form controls
  const submitBtn = form.querySelector('#submit');
  const enteredPassword = form.querySelector('#password');

  const enteredUsername = form.querySelector('#username');
  enteredUsername.addEventListener('input', () => {
    // this.value points to window object, because => preserve the parent context
    submitBtn.disabled = !isValid(enteredUsername.value, REQUIRED);
  });

</script>

</body>
</html>

Congratulations and enjoy learning JavaScript!

Subscribe To My Channel for updates

Modernizing old php project with the help of AI

0. Keep docker running in separate outside of VSCODE terminal 1. The importance of GIT for version control - create modernization branch 2. ...