Category Archives: PHP

Media Streaming (MP4 file streaming) with Apache2

#wget http://h264.code-shop.com/download/apache_mod_h264_streaming-2.2.7.tar.gz

#tar -zxvf apache_mod_h264_streaming-2.2.7.tar.gz

#cd /apache_mod_h264_streaming-2.2.7

#./configure –with-apxs=`which apxs2`

#make

#make install

#LoadModule h264_streaming_module /usr/lib/apache2/modules/mod_h264_streaming.so

#AddHandler h264-streaming.extensions .mp4

#service apache2 restart

The file is attached below in case the main link goes down. The link to the original download location :  http://h264.code-shop.com/download/

Working on Apache/2.4.41 (Ubuntu) on day of writing.

 

apache mod h264 streaming v2.2.7

Google FCM all Push Notification parameters

All Firebase Push Notification parameters are available from the Google API test console. The direct link to the Send method test console – https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages/send

From the above URL other details can be navigated to.

To open the console click on the “Try it!” blue button on right.

Now clicking the blue dots in the basic JSON  will show the relevant params of that section.

 

PHP QR Code Generate

In one of my projects I suddenly needed to generate QR code. I tried searching for some free QR Code generator Library, but didn’t find anything suitable and reliable except the PEAR package which I had used many years back. I was not willing to use the package as the last Alpha release was about 9 years ago. But as there were no suitable package so ultimately used that. The PHP version is 7.2.34.

Using the library is simple and pretty straightforward

Installation:

$pear install channel://pear.php.net/Image_QRCode-0.1.3

PHP Code

require_once './Image_QRCode-0.1.3/Image/QRCode.php';

$qrcode = new Image_QRCode();

$options = array( "image_type" => "png", "output_type" => "return" );

$gd_object = $qrcode->makeCode("STRING", $options);

$sx = imagesx($gd_object);

$sy = imagesy($gd_object);

//The returned object is an "image resource". Which can be saved as an image or can be used as a watermark. Below example is of watermarking which will placed at the bottom right on the main image
//imagesx($im) - $sx === the x position where the qr code will be placed
//imagesy($im) - $sy === the y position where the qr code will be placed
//0, 0 == the start point from where the QRCode image will start to be be copied - 0,0 means from the top left or start of the image - if some other value is given then it will be cropped
//imagesx($gd_object), imagesy($gd_object), == the end point of the qr code image. The current copies upto the bottom right or end point of the image. Any value lesser will cause a cropped image. //75 == is the quality of the overall image.

$im = imagecreatefromstring($data);  // imagecreatefrompng($filename)

imagecopymerge($im, $gd_object, imagesx($im) - $sx, imagesy($im) - $sy, 0, 0, imagesx($gd_object), imagesy($gd_object), 75);

ob_start(); //Turn on output buffering

imagepng($im); //Generate your image

$outputImage = ob_get_contents(); // get the image as a string in a variable

ob_end_clean(); //Turn off output buffering and clean

file_put_contents("IMAGE.PNG",$outputImage);


Website Push Notification with Google Firebase

Mainly three things are needed

  • A file named firebase-messaging-sw.js placed in the root of the website. This file contains the codes for receiving the push when the browser is minimized or that particular website is closed.
  • The scripts for receiving the push
  • The server side code to send the PUSH

 

firebase-messaging-sw.js

//Base library
importScripts("https://www.gstatic.com/firebasejs/7.21.1/firebase-app.js");

//needed for PUSH Message
importScripts("https://www.gstatic.com/firebasejs/7.21.1/firebase-messaging.js");


// Your web app's Firebase configuration
//All these details is available from Firebase Console. The readymade configuration code is available also - please see the attached screenshot
var firebaseConfig = {
apiKey: "xxxxxxxxxxxxxxxxxxx_x-xxxxxxxxxxxx",
    authDomain: "app-name-123456.firebaseapp.com",
    databaseURL: "https://app-name-123456.firebaseio.com",
    projectId: "app-name-123456",
    storageBucket: "app-name-123456.appspot.com",
    messagingSenderId: "123456789012",
    appId: "1:123456789012:web:xxxxxxxxxxxxxxxxxx",
    measurementId: "G-xxxxxxxxxxxx"
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);

const messaging = firebase.messaging();

// If you would like to customize notifications that are received in the
// background (Web app is closed or not in browser focus) then you should
// implement this optional method.
// [START background_handler]
messaging.onBackgroundMessage(function(payload) {
  console.log('[firebase-messaging-sw.js] Received background message ', payload);
  // Customize notification here
  const notificationTitle = payload.notification.title;
  const notificationOptions = {
	body: payload.notification.body,
	icon: 'https://mywebsite.com/icon.png',
	image: 'https://mywebsite.com/logo.png'
  };

  return self.registration.showNotification(notificationTitle,
	notificationOptions);
});
// [END background_handler]

Code for Receiving the Push and processing and displaying the PUSH when the page is open

At present some browsers need user interaction (request raised from an user event handler) to show the access permission popup. The best way to do is to check for permission status (granted or not) and show a Custom popup if not granted. In the custom popup put two buttons – Accept/Yes and Decline/No. On pressing Accept/Yes call the requestPermission function.

When the page is fully loaded (document ready) we are calling the updateUIForPushPermissionRequired function. Inside it we are checking if permission already granted or not. If not granted then we are showing the custom popup


<!DOCTYPE html> 
<html> 
  <head> 
    <meta charset="UTF-8"> 
  </head> 
  <body>
    <div id="notificationPopUp" class="notificationPopup" style="display:none"> 
      <div class="notif-body"> 
        <button id="closeNotification" class="uk-modal-close-default uk-icon uk-close" type="button" uk-close="" onclick="dismissnotificationPopUp()"> 
          <svg width="14" height="14" viewBox="0 0 14 14" xmlns="http://www.w3.org/2000/svg" data-svg="close-icon"> 
            <line fill="none" stroke="#000" stroke-width="1.1" x1="1" y1="1" x2="13" y2="13">
            </line> 
            <line fill="none" stroke="#000" stroke-width="1.1" x1="13" y1="1" x2="1" y2="13">
            </line> 
          </svg> 
        </button> 
        <div class="notif-logo">
          <img src="https://api.wisck.com/logo-wisck.png" alt="" width="100%" height="150">
        </div> 
        <div class="notif-content"> 
          <p class="notif-title">Allow Notifications?
          </p> 
          <p class="text_pop_up">Get notifications of new contents and updates
          </p> 
          <p class="text_pop_up">Notification option can be managed from browser settings.
          </p> 
          <div class="notif-btns"> 
            <button id="blockNotification" class="button-decline" onclick="dismissnotificationPopUp()">No
            </button> 
            <button id="allowNotification" class="button-accept" onclick="requestPermission()">Yes
            </button> 
          </div> 
        </div> 
      </div> 
    </div> 

<div id="snackbar"><p id="snackbarTitle">Title</p><p id="snackbarBody">Body</p></div>
<!-- The core Firebase JS SDK is always required and must be listed first --> <script src="https://www.gstatic.com/firebasejs/8.6.8/firebase-app.js"> </script> <script src="https://www.gstatic.com/firebasejs/8.6.8/firebase-messaging.js"> </script> <!-- TODO: Add SDKs for Firebase products that you want to use https://firebase.google.com/docs/web/setup#available-libraries --> <script> // Your web app's Firebase configuration var firebaseConfig = { apiKey: "xxxxxxxxxxxxxxxxxxx_x-xxxxxxxxxxxx", authDomain: "app-name-123456.firebaseapp.com", databaseURL: "https://app-name-123456.firebaseio.com", projectId: "app-name-123456", storageBucket: "app-name-123456.appspot.com", messagingSenderId: "123456789012", appId: "1:123456789012:web:xxxxxxxxxxxxxxxxxx", measurementId: "G-xxxxxxxxxxxx" }; // Initialize Firebase firebase.initializeApp(firebaseConfig); firebase.analytics(); const messaging = firebase.messaging(); messaging.onMessage((payload) => { console.log('Message received. ', payload); var x = document.getElementById("snackbar"); // Add the "show" class to DIV x.className = "show"; $("#snackbarTitle").html(payload.notification.title); $("#snackbarBody").html(payload.notification.body); // After 3 seconds, remove the show class from DIV setTimeout(function() { x.className = x.className.replace("show", ""); }, 3000); // Update the UI to include the received message. }); function resetUI() { // Get registration token. Initially this makes a network call, once retrieved // subsequent calls to getToken will return from cache. messaging.getToken({ vapidKey: 'xxxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-xxxxx-xxxxxx-xxx' }).then((currentToken) => { if (currentToken) { sendTokenToServer(currentToken); } else { // Show permission request. console.log('No registration token available. Request permission to generate one.'); // Show permission UI. updateUIForPushPermissionRequired(); setTokenSentToServer(false); } }).catch((err) => { console.log('An error occurred while retrieving token. ', err); //showToken('Error retrieving registration token. ', err); setTokenSentToServer(false); }); } // Send the registration token your application server, so that it can: // - send messages back to this app // - subscribe/unsubscribe the token from topics function sendTokenToServer(currentToken) { if (!isTokenSentToServer()) { console.log('Sending token to server...'); // TODO(developer): Send the current token to your server. $.ajax({ url: base_url + 'update-token.php', type: 'post', data: { userId: userId, deviceToken: currentToken, deviceType: "web" }, headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, dataType: 'json', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Access-Control-Allow-Origin': '*', "Access-Control-Allow-Headers": "Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With" }, success: function(response) { console.log('Token sent to server...'); } }); setTokenSentToServer(true); } else { console.log('Token already sent to server so won\'t send it again ' + 'unless it changes'); } } function isTokenSentToServer() { return window.localStorage.getItem('sentToServer') === '1'; } function setTokenSentToServer(sent) { window.localStorage.setItem('sentToServer', sent ? '1' : '0'); } function requestPermission() { $('#notificationPopUp').hide(); //hide the own permission popup - the browser will take over now console.log('Requesting permission...'); Notification.requestPermission().then((permission) => { if (permission === 'granted') { console.log('Notification permission granted.'); // TODO(developer): Retrieve a registration token for use with FCM. // In many cases once an app has been granted notification permission, // it should update its UI reflecting this. resetUI(); } else { console.log('Unable to get permission to notify.'); } }); } function deleteToken() { // Delete registration token. messaging.getToken().then((currentToken) => { messaging.deleteToken(currentToken).then(() => { console.log('Token deleted.'); setTokenSentToServer(false); // Once token is deleted update UI. resetUI(); }).catch((err) => { console.log('Unable to delete token. ', err); }); }).catch((err) => { console.log('Error retrieving registration token. ', err); showToken('Error retrieving registration token. ', err); }); } function updateUIForPushPermissionRequired() { if (Notification.permission != "granted") //if permission not granted yet then show custom popup. { $('#notificationPopUp').slideDown("fast"); //show the custom popup to ask permission. } else requestPermission(); } function dismissnotificationPopUp() { $('#notificationPopUp').hide(); } $(document).ready(function() { updateUIForPushPermissionRequired(); }) </script> </body> </html>

CSS for for the notification popup and the notifications

.notificationPopup {
position: fixed;
top: 0;
left: 50%;
transform: translateX(-50%);
background: #fff;
z-index: 9999;
box-shadow: 1px 2px 10px rgba(0,0,0,.5);
}

.notificationPopup .notif-body {
padding: 15px;
display: flex;
}

.notificationPopup .uk-modal-close-default {
position: absolute;
right: 10px;
top: 10px;
background: 0 0;
border: 0;
}

.notificationPopup .notif-logo {
max-width: 70px;
min-width: 70px;
padding-right: 10px;
}


.notificationPopup .notif-logo img{
margin-top: 50%;
}


.notificationPopup .notif-content .notif-title {
font-size: 18px;
font-weight: 600;
margin: 10px 0;
}

.notificationPopup .notif-content .text_pop_up {
font-size: 16px;
font-weight: 400;
margin: 0;
}

.notificationPopup .notif-btns {
text-align: right;
padding-top: 5px;
}

.notificationPopup .notif-btns .button-decline {
border: 1px solid #ddd;
color: #666;
}

.notificationPopup .notif-btns .button-accept {
border: 1px solid #ec2436;
background-color: #ec2436;
color: #fff;
font-weight: 600;
}

.notificationPopup .notif-btns button {
background: 0 0;
border: 0;
padding: 5px 15px;
cursor: pointer;
margin-left: 10px;
}

.notificationPopup .uk-modal-close-default {
position: absolute;
right: 10px;
top: 10px;
background: 0 0;
border: 0;
}

.uk-close {
color: #999;
transition: .1s ease-in-out;
transition-property: all;
transition-property: color,opacity;
}


/* The snackbar - position it at the bottom and in the middle of the screen */
#snackbar {
visibility: hidden; /* Hidden by default. Visible on click */
min-width: 250px; /* Set a default minimum width */
margin-left: -125px; /* Divide value of min-width by 2 */
background-color: #333; /* Black background color */
color: #fff; /* White text color */
text-align: center; /* Centered text */
border-radius: 2px; /* Rounded borders */
padding: 16px; /* Padding */
position: fixed; /* Sit on top of the screen */
z-index: 9999; /* Add a z-index if needed */
left: 10%; /* Center the snackbar */
bottom: 30px; /* 30px from the bottom */
}

#snackbar p{
color: #fff; /* White text color */
}

#snackbarTitle{
font-weight: bold; /* White text color */
}

/* Show the snackbar when clicking on a button (class added with JavaScript) */
#snackbar.show {
visibility: visible; /* Show the snackbar */
/* Add animation: Take 0.5 seconds to fade in and out the snackbar.
However, delay the fade out process for 2.5 seconds */
-webkit-animation: fadein 0.5s, fadeout 0.5s 2.5s;
animation: fadein 0.5s, fadeout 0.5s 2.5s;
}

/* Animations to fade the snackbar in and out */
@-webkit-keyframes fadein {
from {bottom: 0; opacity: 0;}
to {bottom: 30px; opacity: 1;}
}

@keyframes fadein {
from {bottom: 0; opacity: 0;}
to {bottom: 30px; opacity: 1;}
}

@-webkit-keyframes fadeout {
from {bottom: 30px; opacity: 1;}
to {bottom: 0; opacity: 0;}
}

@keyframes fadeout {
from {bottom: 30px; opacity: 1;}
to {bottom: 0; opacity: 0;}
}

 

Code for sending

<?php
define('SERVER_API_KEY', 'XXXXXXXX:XXXXXXXX-XXXXXX_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-X-');

//FOR WEB ALSO TOKENS GET GENERATED. 
$tokens = ['XXXXXXXXXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-XXXXXXXX-XXXXXXXX-XXXXXXXX',
'XXXXXXXXXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-XXXXXXXX-XXXXXXXX-XXXXXXXX'
];

$header = [
     'Authorization: Key= ' . SERVER_API_KEY,
     'content-Type: Application/json'
];

$notification = [
      'title' => 'Testing Notification',
      'body' => 'Testing Notification Body',
      'icon' => '',
	  'sound' => 'default',
	  'click_action' => "android.intent.action.MAIN"
];

$data = [
      'title' => 'Testing Notification',
      'body' => 'Testing Notification Body',
      'icon' => '',
	  'sound' => 'default',
];

$options = [
	'priority'=> 'high'
];

$payload = [
       'registration_ids' => $tokens,
	   'notification' => $notification,
	   'data' => $data,
	   'options' => $options
];

$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => "https://fcm.googleapis.com/fcm/send",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => "POST",
  CURLOPT_POSTFIELDS => json_encode( $payload ),
  CURLOPT_HTTPHEADER => $header,
));

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err) {
  echo "cURL Error #:" . $err;
} else {
  echo $response;
}
?>

 

Google Firebase Web Push – Public VAPID Key
Google Firebase Web Push – Web app configuration

 

Please note this code will show two popups in background mode – that is because Push is being sent as “Notification”. Browser is handling that and showing one on its own. And another from the backgroundHandler code in Service Worker file. For showing only the custom popup use “Data” instead of “Notification” in the Push body.

 

How to find list of all FCM parameters https://www.kolkataonweb.com/code-bank/miscellaneous/google-fcm-all-push-notification-parameters/

Playing RTMP in Browser without FLASH

RTMP is used for streaming live video. With a bit of manipulation of the frontend codes it can also be used to play audio only (the below code does that)

Now the thing is playing RTMP link in browser requires Flash which is not supported by Apple and Linux based OS. The solution is to use the HLS link instead of the RTMP link. The HLS format is supported by most browsers and by Apple and Linux based OS also.

One thing to note is the MIME type of the source.

There are various Javascript libraries that can be used to build the player. Below is an example using Video.js

This internally uses the http-streaming library of Videojs. Details of the library can be found here  This library is included in video.js 7 by default. Hence in the below code  it has not been added separately

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Live Streaming</title>
    <link href="https://vjs.zencdn.net/7.6.6/video-js.css" rel="stylesheet" />

	<!-- If you'd like to support IE8 (for Video.js versions prior to v7) -->
	<script src="https://vjs.zencdn.net/ie8/1.1.2/videojs-ie8.min.js"></script>
	<script src="https://vjs.zencdn.net/7.6.6/video.js"></script>
</head>
<body>
<audio id="player" class="video-js vjs-default-skin" height="70" width="300" controls autoplay preload="none">
    <source src="https://rtmpserverBaseUrl/path/streamName.m3u8" type="application/x-mpegURL" />
</audio>

<script>
    var player = videojs('#player');
    videojs('player').ready(function() {
       this.play();
    });
</script>

<style>
.vjs-seek-to-live-control,
.vjs-fullscreen-control,
.vjs-picture-in-picture-control
 {
   display: none;
 }
</style>

</body>
</html>

Code courtesy – https://github.com/videojs/http-streaming

Both libraries used in the code can be downloaded from here
videojs version 7.6.6
videojs-ie8.min version 1.1.2

Two Way Encryption or Hashing using Key

This is using PHP and openssl_decrypt/openssl_encrypt

Encrypting the string

$key = "xxxxxxxxxxx"; //11 characters
$ivlen = openssl_cipher_iv_length("aes-256-cbc-hmac-sha256");
$iv = openssl_random_pseudo_bytes($ivlen);
$hash = openssl_encrypt(STRING TO HASH,"aes-256-cbc-hmac-sha256",$key,0,$iv);
$iv = bin2hex($iv); // iv generated is in binary - converted to HEX for passing through SESSION or POST or URL

Decrypting back the string

$key = "xxxxxxxxxxx";
$hash = HASH FROM ENCRYPTION;
$iv = IV FROM ENCRYPTION STEP; //note this is in HEX and needs to be converted back to BIN 
$iv = hex2bin($iv); //convert the IV in HEX to BIN

$decryptedString = openssl_decrypt($hash,"aes-256-cbc-hmac-sha256",$key,0,$iv);

Feel free to explore other algorithms

Legends in Morris Chart

With help from this article https://github.com/morrisjs/morris.js/issues/346

This is about adding Legends to Morris charts. Though Morris chart shows legend on hovering on the graphs, but I wanted to show a legend permanently on one corner of the chart area.

Below are the codes. It is mostly plug and play code

The div in which the chart will be displayed

<div class="box-body chart-responsive">
    <div id="visitor_legend" class="bar-chart-legend"></div> <!-- the legend area -->
    <div class="chart" id="bar-chart" style="height: 300px;"></div> <!-- the chart area -->
</div>

The CSS

<style>
.bar-chart-legend {
	display: inline-block;
	right: 25px;
	position: absolute;
	top: 8px;
	font-size: 10px;
}

.bar-chart-legend .legend-item {
	display: block;
}

.bar-chart-legend .legend-color {
	width: 12px;
	height: 12px;
	margin: 3px 5px;
	display: inline-block;
}
</style>

The JS code

// Legend for Bar chart
bar.options.labels.forEach(function(label, i) {
	var legendItem = $('<span class="legend-item"></span>').text( label).prepend('<span class="legend-color">&nbsp;</span>');
	legendItem.find('span').css('backgroundColor', bar.options.barColors[i]);
	$('#visitor_legend').append(legendItem) // ID pf the legend div declared above
});

Morris charts documentation https://morrisjs.github.io/morris.js/lines.html