Showing posts with label Web Application. Show all posts
Showing posts with label Web Application. Show all posts

Saturday, July 31, 2021

Wait for State Changes with Redux Saga

Hello,

As we know Redux saga allows us to respond to actions outside Redux store. It's kind of middleware library to handle side effects with ease. This side effect could be anything like calling APIs, doing some IO operations or anything. While working with Saga sometime it happens that we also want to detect state changes and do some actions after it. In this blog I am going to explain how you can wait or detect Redux state changes with Saga.

Let's understand with an example. For example there is an API call to get access token and as soon as you have access toke available in state you want to call some other actions like background sync etc. 


function* waitForLoginToken(selector) {

    if (yield select(selector)) return;

    while (true) {

      yield take('*');

      if (yield select(selector)) return;

    }

}

export function* postSignInAction(payload) {

    cost loginTokenSelector = state => state.auth.loginToken;

    yield call(waitForLoginToken, loginTokenSelector);

    yield put({ type: 'BACKGROUND_SYNC' });

}

function* mySaga(){

  yield takeEvery('SIGN_IN', postSignInAction);

}

As you can see in above code, we take every sign in action and call postSignInAction which will wait for state change.

We defined state selector as state.auth.loginToken. Till the time loginToken is not set in state.auth it will wait as we are using while loop to wait for state change. Once we get it in state we call next action. 

This way you can & detect state change with Redux Saga. Hope this helps you.

Saturday, July 17, 2021

React-Draft-Wysiwyg - Find Text Option

Hello,

Recently I was working on POC for rich text editor using React-Draft-Wysiwyg editor. 

There we have a requirement to add find & replace dialog box which should find the matching text from all the blocks and height it with background color. For the POC we added find text functionality. Here in this blog I will explain how to do it. 

For this I have created separate React component and add it as custom option to editor toolbar. Let's understand it step by step. 

If you want to know how to add custom option you can find reference from here.

https://jpuri.github.io/react-draft-wysiwyg/#/docs

1) Create Modal with Text input and Button

Please note I have used grommet UI library to build the POC. So text input and button was imported from Grommet.

<TextInput

    data-cy="find-text"

    autoFocus

    onChange={this.onChangeFindText}

    value={this.state.findText}

/>

<Button

    id="find"

    label="Find"

    onClick={this.onFindClick}

/>

2) Handle Find Click Event

onFindClick = () => {

  const search = this.state.findText;

  let contentState = convertToRaw(this.props.editorState.getCurrentContent());

  contentState.blocks.forEach(block => {

    const text = block.text;

    const matches = [...text.matchAll(search)];

    if(matches.length > 0) {

      matches.forEach(match =>{

        block.inlineStyleRanges.push({length: match[0].length,

          offset: match.index,

          style: "bgcolor-rgb(247,218,100)"

        })

      });

    }

  });

  let newEditorState = {

    editorState: EditorState.createWithContent(convertFromRaw({blocks: contentState.blocks,entityMap: {}})),

    contentState: null

  }

  this.props.onChange(EditorState.createWithContent(convertFromRaw({blocks: contentState.blocks,entityMap: {}})));

}

In above code we are getting search text from the state and matching it with texts of all custom blocks. Where ever it matches we are setting inline styles in blocks with yellow color background. and then setting state of editor again with new blocks. 

Hope this helps you.

Saturday, June 26, 2021

How to Get Video Thumbnails with Javascript

Hello,

In this blog we will see how you can generate thumbnail of video using JavaScript.  Let's assume you have file upload in your HTML as following.

<input type="file" id="uploadVideo" accept="video/mp4" />

Now let's add an onChange listener for this.

document.querySelector("#uploadVideo").addEventListener('change', function() {
    var inputFile = document.querySelector("#uploadVideo").files[0];
    getVideoThumbnail(inputFile)
});

Now when you upload video it will call this function and you can access this video by using files property. Now we got the file. First step we will do is get blob URL of video so we can access metadata of video. Check below function. 

Here first what we are doing is creating video element and assigning blob URL to it from input file using URL.createObjectURL method.

Then we have added event listener for meta data. This is necessary as we can't get video data till them time meta data is loaded. 

Then we seek video to 0.0 second. You can add your own time here in case if you need. Then we have added seeked listener. By this time we have video data is available. Now we are using canvas to drawImage from video frame data.

Then using toDataURL method we get the base64Data. Here 0.60 is value of quality. If you don't want to compromise quality of image then you can pass 1 here.  

function getVideoThumbnail(inputFile) {
  try {
    let video = document.createElement('video');
    let blobSrc = URL.createObjectURL(inputFile);
    video.setAttribute('src', blobSrc);
    video.addEventListener('error', () => {
        console.log("Error")
    });
    video.addEventListener('loadedmetadata', () => {
        setTimeout(() => {
          video.currentTime = 0.0;
        }, 200);
        video.addEventListener('seeked', () => {
            let canvas = document.createElement('canvas');
            video.pause();
            canvas.width = 400
            canvas.height = 400;
            let ctx = canvas.getContext('2d');
            ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
            var base64Data = ctx.canvas.toDataURL(
                'image/png',
                0.60
            );
            // SET this data in SRC of image tag or you can add your own logic.
        });
    });
     video.load();
  } catch (err) {
  
  }
}

Hope this helps you.

Tuesday, August 20, 2019

ReactJs Material UI Table Infinite Scroll

Hello,

Recently in one of my ReactJs project, I faced a challenge in implementing infinite scroll in Material UI table. In this blog I am going to mention trick I have used.

First of all I was really surprised to see that Material UI table does not have infinite scroll function out of the box. It's very much needed. Sometimes something can not be achieved with frameworks, can be achieved via basics of JavaScript. In this I have done something similar.

I tried adding on scroll events on Table, Table Body but it didn't work. I also tried adding refs to body and then bind the Scroll event but that also did not work. After struggling for couple of hours, I finally decided to it with Pure JavaScript.

Step 1 : Wrap material UI table inside the container with fixed height and set overflow = scroll to container.


import styled from "styled-components";

export const Table = props => (
  <TableWrapper id={props.id}>
    <MuiTable {...props}/>
  </TableWrapper>

);

const TableWrapper = styled.div`
  max-height: 500px;
  overflow: scroll;

  ::-webkit-scrollbar {
    width: 3px;
    height: 3px;
  }
`;

As you can see I created a wrapper of table and set max height to it. You can make it dynamic as well depending on window height.

Step 2: Import Table to your component

import {
  Table

 } from './components/Table';

return (
          <>         
             <Table id={"tableID"}/>
          </>
        );

Step 3: Bind scroll event to wrapper

let me = this;
document.getElementById('tableID').onscroll = function(event){
   if(this.scrollTop == (this.scrollHeight - this.clientHeight)){
         //User reached bottom of table after scroll
         //Logic to call web services to get next set of data
   }
};

Hope this helps you.

Monday, August 19, 2019

Accessing Data From Redis Using NodeJs

Hello,

When you are working with business applications, it's sometimes need to cache the data. At this point Redis can be very useful, it can be used as database or cache database. You can store any kind of data like strings, JSON objects etc. in Redis.

Problem we face while working with NodeJs and Redis, get data operation from Redis is Asynchronous operations so it gives you callback and your code execution will continue. This may create a problem when you want to handle it in Synchronous way. For example you may have loops inside that you are trying to access data from Redis.

In this blog I am going to explain how you can have Synchronous operations. In nutshell we got to promisify the redis module.

There is a library called bluebird, that can be used for this. Lets go step by step.

Step 1

Install bluebird and redis in your NodeJs app.

npm install bluebird
npm install redis

Step 2

Import it in NodeJs app.

var redis = require('redis');
var bluebird = require("bluebird");

Step 3

Promisify Redis.

bluebird.promisifyAll(redis.RedisClient.prototype);
bluebird.promisifyAll(redis.Multi.prototype);

Step 4

Connect to Redis client.

var client = redis.createClient();
    client.on('connect', function() {
    console.log('Redis client connected');
});

Step 5

Use Async version of get function to get data.

client.getAsync("MY_KEY").then(function(res) {
      //Access Data
});

This is how you can have Sync operations with Redis. 

Friday, April 20, 2018

Laravel ValidationException Handling

This is the creepiest thing I have ever fixed in Laravel. I can't even imagine that in Laravel we can have such creepy problem. But anyways other than this I really like Laravel framework.

First let me explain the problem. In our Laravel 5.5 application we have added exception handling in app/Exceptions/Handler.php file

public function render($request, Exception $exception)
{
    Redirect::to('admin/errorPage')->send();
}

Now the problem was in case of form validations it was throwing ValidationException so in case of returning back to form it always took me to the error page and I am not able to see what are the validation issues. Now that was really strange. So there were two options . First, I have to remove server side validations so it does not throw ValidationException and we shall do all client side validations. Or find out some other way to handle this.

So after 3 to 4 hours of struggle of going though framework code and documentation and online help I finally figure out the solution. Here are steps to add it.

1) Step 1 : Add  ValidationException in dontReport field in app/Exceptions/Handler.php

protected $dontReport = [
   //
   \Illuminate\Validation\ValidationException::class
];

2) Step 2 : Update the render method declaration

public function render($request, Exception $exception)
{
    if($this->shouldReport($exception)){
       Redirect::to('admin/errorPage')->send();
    }else{
       return $this->convertValidationExceptionToResponse($exception, $request);
    }
}

So here first we are checking if the current exception to be reported or not by checking shouldReport function

If not to be reported then we are using convertValidationExceptionToResponse method of super class to generate the response and send it back.

Please note that this solution will only work

Sunday, February 25, 2018

Scroll Two Divs Together

Recently in one of my project there was a requirement to maintain scroll positions of two divs. In UI there are two divs side by side. If user scrolls on left DIV then right div should also be scrolled and if user scrolls on right DIV then left div should also be scrolled. So here is how to do this.

var leftPart = document.getElementById('leftPart');
var rightPart = document.getElementById('rightPart');

Now lets add scroll event on both.

leftPart.onscroll = function() {
    rightPart.scrollTop = this.scrollTop;
}

rightPart.onscroll = function() {
    leftPart.scrollTop = this.scrollTop;
}

That's it now both should scroll no but wait it makes your UI unresponsive because there is a deadlock. While right one is scrolling, it will also scroll left one and at the same time it will also fire event and will try  to scroll right one again and there is DEADLOCK.........

So to prevent it, we have to add flags to check if one is already scrolling then hold the event.

so lets have two flags.

var isSyncingLeftScroll = false;
var isSyncingRightScroll = false;

and use it in scroll event.

leftPart.onscroll = function() {
  if (!isSyncingLeftScroll) {
    isSyncingRightScroll = true;
    rightPart.scrollTop = this.scrollTop;
  }
  isSyncingLeftScroll = false;
}

rightPart.onscroll = function() {
  if (!isSyncingRightScroll) {
    isSyncingLeftScroll = true;
    leftPart.scrollTop = this.scrollTop;
  }
  isSyncingRightScroll = false;
}

That's it and now you will have smooth scrolling effect on both the DIVs. Hope this helps you.

Sunday, February 4, 2018

Some Tips and Tricks of Working With Bootstrap Select2 Control

Hello,

Since I am a web developer, I used to work  a lot with Bootstrap Select 2 Control. Here I am going to share some quick tips and tricks of working with Select 2 controls.

1) Dynamically create Select2 control with JavaScript

When we are working on dynamic websites, sometimes we also have to create select2 controls dynamically. Most of the developers faces issues here. Because select2 control is created by JavaScript on document ready. So if you want create it dynamically, first append basic html of control inside and the by using JavaScript init it.

Something like this.

$('.select2').select2();

Sometimes it takes time to get reflect in DOM so in this case you may have to give some timeout.

setTimeout(function(){
      $('.select2').select2();
},500);

2) Open Select2 dropdown on focus.

This is one more UX experience. Most of the web users are used to work with TAB. So in your form if you have select2 control and you come on it via tab. It should open dropdown.

Here is how we can do it.

$(document).on('focus', '.select2', function() {
if($(this).prev().val() == ''){
  $(this).siblings('select').select2('open');
}
});

3) Open Select2 dropdown with down arrow key

This is one more UX experience. Most of the web users are used to work with up and down arrow while working with dropdown. So in case of select2 they are expecting the same result.

$(document).on('keydown', '.select2', function(event) {
    if(event.keyCode == 40){
    $(this).siblings('select').select2('open');
    }
});

4) Keep focus on Select2 after selecting item and dropdown is closed.

In new version of Select2 there is a bug that after you select an item and dropdown is closed. It will lost focus. So to keep focus on the control, use following code.

$('select').on(
  'select2:close',
  function () {
  $(this).focus();
  }
  );
},1000);

Hope this tips helps you in your development with Select2.

Friday, February 2, 2018

Amazon EC2 Laravel Not Live After " php artisan up " Command

Hello,

This blog post is about quick tip for the users who have deployed Laravel application on Amazon EC2 instance.

Recently we had Laravel application deployed on Amazon EC2 instance where we put site on maintenance mode with command

php artisan down

Worked properly, site was in maintenance mode and displayed

Be Right Back screen.

After sometime we tried to make site up and running by

php artisan up

Didn't work as site was still displaying

Be Right Back screen

Tried to clear the cache and config with

php artisan cache:clear
php artisan config:clear

But still it didn't worked. After 5 to 10 mins to struggle, found out an issue. It was because of file permission issue.  When you put site to maintenance mode, it creates

storage/framework/down folder

When you run

php artisan up

This folder should be removed. However in my case I was not using root user hence this file was not deleted.

So solution is

go to storage/framework folder and run command

rm -rf down

and that's it, your site is up and live.

Hope this helps you. 

Thursday, September 7, 2017

jQuery Submit Form with Ajax

Hello,

In this blog we are going to take a look at how we can submit for with Ajax using jQuery.

First of all add jQuery file in your head section of HTML page.

<script src="jquery.min.js"></script>

Now we will have following form.

<form action="">
      <input id="text" autocomplete="off" placeholder="Type here" />
</form>

If you want to submit this form with Ajax using jQuery, first you have to do is add submit event handler.

$(function () {
$('form').submit(function(){
var formData = JSON.stringify($('form').serializeArray());
$.ajax({
type: "POST",
url: "YOUR_API_URL",
data: formData,
success: function(data){

},
failure: function(errMsg) {
}
});
return false;
    });
});

So first we have added submit event handler and used return false so it does refresh the whole page and just use the Ajax request.  Inside event handler we are using HTML 5 FormData to get form data first and then using Ajax request to send data to server in APIs.

Hope this helps you.

Friday, May 26, 2017

PHP strtotime() does not work with dd/mm/yyyy Format

Hello,

This is quick blog regarding PHP strototime function. In our recent project we were importing data from CSV where we faced two issues.

1) If we try to import date like 01/05/2016 considering dd/mm/yyyy format, it saves date in database as 2015-01-05

2) If we try to import date like 31/08/2016 considering dd/mm/yyyy format, it saves data in database as 1970-01-01

In short month and day is swiped while saving. So in case of date like 31/08/2016,  31 is assumed as month and there is no such month in calendar so it gave error and returns date like 1970-01-01

This is first time we faced such issue. I was not sure what's the exact issue but I assumed it has something to do with separator. So we tried same dates with  - instead of / and it worked. So to solve this temporary, we had following solution.

$date = '31/08/2016';
$date = str_replace('/', '-', $date);
echo date('Y-m-d', strtotime($date));

So we replace / with - and it worked but solving problem is not enough, we shall go in deep to check why we had this problem so curiously I looked into function documentation of strtotime and found out following.

"Dates in the m/d/y or d-m-y formats are disambiguated by looking at the separator between the various components: if the separator is a slash (/), then the American m/d/y is assumed; whereas if the separator is a dash (-) or a dot (.), then the European d-m-y format is assumed. "

So indeed the problem here was with the separator.

Hope this helps you.

Thursday, March 30, 2017

PHP Debugging - Look for Case Sensitivity In Variable, File Names and Class Names

This blog is coming out of conversation with one of the developer in my team. He recently made some changes in API in local development and push code to test server. But on server it was throwing an error and API was not working. So after trying hard for sometime he came to me and asked for help. He showed me lines of code he has added and as an experienced person I immediately caught his error. The problem was, he declared variable in lowercase and was using variable with uppercase in next line and that's what breaking on server. Something like this

$var = new Class();
$VAR->prop = value;

Case sensitivity is one of the major reason for errors while you are working on local development environment with XAMPP, WAMP in Windows. At this time case sensitive is not applied and it will  treat

$var;
$VAR;
$Var;

as one and the same variables. But when you are working on server, you have unix / linux operating systems like Ubuntu, Fedora etc. At this time case sensitivity is applied and

$var;
$VAR;
$Var;

Are treated as three different variables. So by mistake if you declare it with lower case and try to use it upper case, it will give you an error. So if you are facing this issue that, code works on your local machine, but does not work on server look for the case sensitivity.

Same goes for the filenames and class names. If you have adde file with name

Myclass.php

and if you include it with

include 'MyClass.php';
require 'MyClass.php';

Then it will not be able to find file and it will throw warning or fatal error if you are using require. So make sure that you maintain case sensitivity while naming your class, variables and files in PHP because ultimately your code will be pushed to UNIX / LINUX server and it is case sensitive. 

Monday, March 6, 2017

PHP file_get_contents throws 400 Bad Request Error - Google Geocode API

Recently I was using Google Maps API to geocode address with PHP. There were thousands of addresses in CSV and I have to read it one by one and do geocode it and get lat long and other missing info of the address. So I was using file_get_contents function to fire HTTP request and get output like this.

$geocode = file_get_contents('https://maps.google.com/maps/api/geocode/json?address='.urlencode($records[0]).'&key=API_KEY&sensor=false');
$output = json_decode($geocode);

It worked for few address but for some addresses it throws error.

ErrorException in Controller.php line 535:
file_get_contents(URL): failed to open stream: HTTP request failed! HTTP/1.0 400 Bad Request

That's because some of the addresses in the CSV were not properly formatted and there were some special characters in it as addresses were copied from web pages. But the problem was it's eventually breaking the execution of the script. So to fix it use PHP curl instead of file_get_contents. As it does not throw exception on bad request but it gives you response code and that you can check before you get output. So here is my code.

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://maps.google.com/maps/api/geocode/json?address='.urlencode($records[0]).'&key=APIKEY&sensor=false');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$geocode = curl_exec($ch);

if(curl_getinfo($ch, CURLINFO_HTTP_CODE) === 200) {
        // convert response
        $output = json_decode($geocode);
if($output->status == 'OK'){

}
}
curl_close($ch);

So as you can see on above code, we are using checking CURLINFO_HTTP_CODE, if it's 200 that means HTTP request is successfully executed or in case there is a bad request you can check it and skip accessing the output. So it won't throw an error.

Saturday, October 22, 2016

Send FireBase Push notifications from PHP Application

Hello,

Recently in one of my project we have mobile applications with PHP web services. In this we have a requirement to send Firebase Push notifications from PHP to mobile app. Here in this blog I am going to explain how to do this.

First all login to your Firebase console and get the Web Api key. Go to https://console.firebase.google.com/ and login with your user name and password.

Select your project



Click on gear icons on left and select project settings and above screen will be displayed. Here Web Api Key is the key which you need. copy it. Now let see code one by one.

$url = 'https://fcm.googleapis.com/fcm/send';

This is the URL we will use to send push notification.

Now lets build the payload.

$fields = array (
'to' => 'REGISTRATION_KEY',
"notification" => array(
"title"=> "Welcome To App",
"body"=> "App Description"
),
"data"=>array(
"key_1"=>"value_1",
                        "key_2"=>"value_2"
)
);

Here to is the filed which contains registration id for the device. This is the id which you get when you register device for push notification.

notification contains title and text to be displayed in notification area. This is a standard format and should not be changed.

data contains all the user defined data you want to send with notification, you can add any number of key value pairs here.

If you don't want to pass any data, remove the data field from payload. So now payload is read now lets encode it to send.

$fields = json_encode ( $fields );

Now send headers with API key.

$headers = array (
'Authorization: key=' . "YOUR_WEB_API_KEY",
'Content-Type: application/json'
);

Now we will use PHP cURL to send HTTP request.

$ch = curl_init ();
curl_setopt ( $ch, CURLOPT_URL, $url );
curl_setopt ( $ch, CURLOPT_POST, true );
curl_setopt ( $ch, CURLOPT_HTTPHEADER, $headers );
curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, true );
curl_setopt ( $ch, CURLOPT_POSTFIELDS, $fields );

$result = curl_exec ( $ch );
echo $result;
curl_close ( $ch );

That's it and Push notification is sent to particular device.

Saturday, September 17, 2016

osTicket, Create Ticket with API

Hello,

Recently for one of my project we have a requirement to integrate laravel application and osTicket. Data from laravel app to be sent to osTicket and create ticket with that.

Now we all know that in osTicket if send an email, it will automatically create ticket. However in our case it won't work as emails were from different domains so we have to use osTicket API.

First of all you have to create API key for that login to your osTicket admin panel and go to.

Admin Panel -> Manage -> API keys and create new API key.


Here IP address is your source IP address from where you will call an API. In our case it was server IP address. Now API key is created. Following is the code.

$config = array(
'url'=>'http://yourosTicketURL/api/tickets.json', 
'key'=>'yourapikey'  // API Key goes here
);


In above code replace yourosTicketURL with your URL and replace yourapikey with your generated key.

Now prepare data to send.

$name = 'Name of User';
$email = 'Email of User';
$mobile = 'Mobile';
$subject = 'Subject';
$text = 'Dummy message';

$data = array(
'name'      =>     $name,
'email'     =>      $email,
'phone' =>     $mobile,
'subject'   =>      $subject,
'message'   =>   "data:text/html;charset=utf-8,$text",
'ip'        =>      $_SERVER['REMOTE_ADDR'],
'topicId'   =>      '1',
'attachments' => array()
);

Now we will send data to API.

#pre-checks
function_exists('curl_version') or die('CURL support required');
function_exists('json_encode') or die('JSON support required');

#set timeout
set_time_limit(30);

#curl post
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $config['url']);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_USERAGENT, 'osTicket API Client v1.333');
curl_setopt($ch, CURLOPT_HEADER, FALSE);
curl_setopt($ch, CURLOPT_HTTPHEADER, array( 'Expect:', 'X_API_KEY: '.$config['key']));
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, FALSE);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
$result=curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($code != 201)
die('Unable to create ticket: '.$result);

$ticket_id = (int) $result;

# Continue onward here if necessary. $ticket_id has the ID number of the
# newly-created ticket

function IsNullOrEmptyString($question){
return (!isset($question) || trim($question)==='');
}

That's it and it should work. No wait if you run you will always get following error.

Unable to create ticket:  Invalid API key.

Now that was really strange as API key was valid, IP address was valid everything is good but still it does not create ticket. So what to do. Well there is a bug in osTicket API code. After spending couple of hours I finally figure out the solution. We have to modify osTicket source code for this. Open following file.

include/class.api.php

And find out following functions.

function requireApiKey() {
        # Validate the API key -- required to be sent via the X-API-Key
        # header

        if(!($key=$this->getApiKey()))
            return $this->exerr(401, __('Valid API key required'));
        elseif (!$key->isActive() || $key->getIPAddr()!=$_SERVER['REMOTE_ADDR'])
            return $this->exerr(401, __('API key not found/active or source IP not authorized'));

        return $key;
    }

    function getApiKey() {

        if (!$this->apikey && isset($_SERVER['HTTP_X_API_KEY']) && isset($_SERVER['REMOTE_ADDR']))
            $this->apikey = API::lookupByKey($_SERVER['HTTP_X_API_KEY'], $_SERVER['REMOTE_ADDR']);

        return $this->apikey;
    }

Here the problem was it never get HTTP_X_API_KEY and REMOTE_ADDR was never set. So replace above two function with following code.

function requireApiKey() {
        # Validate the API key -- required to be sent via the X-API-Key
        # header
        if(!($key=$this->getApiKey()))
            return $this->exerr(401, __('Valid API key required'));
        elseif (!$key->isActive() || $key->getIPAddr()!=$_SERVER['REMOTE_ADDR'])
            return $this->exerr(401, __('API key not found/active or source IP not authorized'));

        return $key;
    }

    function getApiKey() {
 
  foreach (getallheaders() as $name => $value) {
  $_SERVER['HTTP_'.$name] = $value;
  }
    if (!$this->apikey && isset($_SERVER['HTTP_X-Api-Key']) && isset($_SERVER['REMOTE_ADDR']))
            $this->apikey = API::lookupByKey($_SERVER['HTTP_X-Api-Key'], $_SERVER['REMOTE_ADDR']);

        return $this->apikey;
    }

As you can see in above code we are getting all headers we set when we call API and put it in $_SERVER variable. and instead of REMOTE_ADDR we are using HTTP_X_REAL_IP.  Now save the file and again run API code. It should work fine.




Saturday, June 18, 2016

JavaScript Create Date With TimeZone

Hello,

Recently in one of my project we faced lots of issues regarding in correct dates displayed to users. The problem was TimeZone. A user is in India but he don't know that he has set timezone to USA timezone and hence we get user's device date it was showing wrong date and time.

We asked our users to fix it but as we know end users are always unpredictable they still set the timzone to USA or others and keep complaining us about dates and times.

So here is what we did to fix this issue.

Step 1 : Get User's Current Location

You can use HTML 5 GeoLocation.

if (navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(gotUserPosition);
}

Step 2 : From the Latitude and Longitude, get user's current timezone using Google API.

function gotUserPosition(position){

     Ext.Ajax.request({
            url: 'https://maps.googleapis.com/maps/api/timezone/json?       location='+ position.coords.latitude +','+position.coords.longitude+'&timestamp='+parseInt(Date.now()/10)+'&key=YOUR_KEY',
            method: 'GET',
            disableCaching: false,
            success: function(response) {
                var result = Ext.decode(response.responseText);
                if(result.status == 'OK'){
                    localStorage.setItem('time_offset',result.rawOffset);
                    localStorage.setItem('timeZoneId',result.timeZoneId);
                }
            },
            failure: function(response) {
             
            },
            scope: this
     });

}

For this you have to create a Google API project and enable timezone API and add your key in stead of YOUR_KEY

As you can see above we are sending user's latitude and longitude to google maps api and getting the result. If result is OK. then we are saving time offset to local storage.

Now this time offset is the offset in number of seconds from UTC time. For example Indian Standard Time is ahead of UTC for 5 hours and 30 minutes. So here my offset will be 19800 seconds which is 5 hours and 30 minutes.

Now use the following logic to create date object.


var utcDate = (new Date()).toISOString();
var offsetHours = parseInt(Number(localStorage.getItem('time_offset'))/60/60);
var offsetMinutes = parseInt(Number(localStorage.getItem('time_offset'))/60%60);

var currentDate = new Date(Date.UTC(Number(utcDate.split('T')[0].split('-')[0]), Number(utcDate.split('T')[0].split('-')[1]) - 1, Number(utcDate.split('T')[0].split('-')[2]), (Number(utcDate.split('T')[1].split(':')[0]) + Number(offsetHours)), (Number(utcDate.split('T')[1].split(':')[1]) + Number(offsetMinutes)),0));

function z(n){return (n < 10? '0' : '') + n;};

var currentDateString = currentDate.getUTCFullYear() + '-' + z(currentDate.getUTCMonth() + 1) + '-' + z(currentDate.getUTCDate());

So above logic about creating UTC date and then adding number of hours and minutes to it to get desired date and time in UTC timezone. So virtually it's UTC date and time but since we added offset it will show you local date and time.

Hope this helps you.



Thursday, May 5, 2016

Create Dynamic Half Circular Progress Bar With HTML 5 CSS 3 - Create Gauge Chart In HTML 5

Recently in one of my project there was a requirement to create half circle gauge chart to show progress of some actions. Something like below image


So first of all I decided to use some charts library to create UI like this but since this was mobile application I do not find any suitable chart library. So I decided to build UI from scratch. So here is the step by step guide. 

First our basic HTML and CSS

<div style="visibility: hidden" class="container" id="container">
                       <div id="border" class="active-border">
                            <div id="circle" class="circle">
                               <div id="needle" class="needle"></div> 
                            </div>
                        </div>
                      </div>

Now the basic CSS.

.container{
    width: 100%;
    height: 100%;
    overflow: hidden;
    position: relative;
    top: -25%;
}

.circle{
    position: relative;
    top: 5px;
    left: 5px;
    text-align: center;
    width: 200px;
    height: 200px;
    border-radius: 100%;
    background-color: rgba(0,0,0,1);
}

.border{
    position: relative;
    text-align: center;
    width: 210px;
    height: 210px;
    border-radius: 100%;
    top : 50%;
    background-color:#00a651;
}

.needle {
    position: absolute;
    background-color: #f0566f;
    height: 100%;
    width: 0.5%;
    left: 50%;
}

.needle:before {
    content: "";
    position: absolute;
    top: 0px;
    left: -10px;
    width: 0px;
    height: 0px;
    border-top: 10px solid transparent;
    border-right: 20px solid #f0566f;
    border-bottom: 10px solid transparent;
    -webkit-transform: rotate(90deg);
}

Now here comes the dynamic things. first of we have to set height and width of all the elements inside container to screen width and height.

var containerWidth = 0;

if(document.getElementById('container').clientHeight > document.getElementById('container').clientWidth){
containerWidth = document.getElementById('container').clientWidth;
}
else{
containerWidth = document.getElementById('container').clientHeight;
}

var circleWidth =  containerWidth - 10;
var activeBorderWidth =  containerWidth;
var padding = (document.getElementById('container').clientWidth - document.getElementById('container').clientHeight) / 2;

document.getElementById('circle').style.width = circleWidth + 'px';
document.getElementById('circle').style.height = circleWidth + 'px';
document.getElementById('container').style.paddingLeft = padding + 'px';

document.getElementById('border').style.width = activeBorderWidth + 'px';
document.getElementById('border').style.height = activeBorderWidth + 'px';

So as you can see we are setting border with to container width and make it fit inside container and setting inner circle width to bit less than border width to create circular progress bar. Now we calculate transform degrees to set up liner gradient to show progress. 

var degree = (180 * Number(count)) / (Number(total));

document.getElementById('border').style.background = '-webkit-linear-gradient('+degree+'deg, #9a9a9a 50%, #00a651 50%)';

As you can see since we have half circle we are calculating degrees by 180. If you want full circle progress bar then calculate it with 360 degree.                 

Now set needle transformation.

var needleTransformDegree = 180 - degree;

document.getElementById('needle').style.webkitTransform = 'rotate('+needleTransformDegree+'deg)';
               
document.getElementById('container').style.visibility = 'visible'

That's it and end result look something like below.


Hope this helps you.

Saturday, March 19, 2016

Laravel App Not Working in Iframe in Internent Explorer

Recently in one of my project we faced strange issue. We have one application running from one domain. This application has an iFrame which is loading laravel app from other domain. This laravel app has certain ajax requests. The issue was this laravel app and ajax requests were working fine in Chrome and other webkit browser however it was not working in Internet Explorer.

After few ours of struggle we found a solution. Actually it was an issue of cookies being blocked by Internet Explorer. We all know that laravel app creates certain cookies on the front end. This was blocked by Internet Explorer hence Ajax requests were not working as it was unable to find cookies. First of let me explain what exactly was the issue and then we will look for solution.

Internet Explorer gives lower level of trust to IFRAME pages (IE calls this "third-party" content). If the page inside the IFRAME doesn't have a Privacy Policy, its cookies are blocked (which is indicated by the eye icon in status bar, when you click on it, it shows you a list of blocked URLs).

In this case, when cookies are blocked, session identifier is not sent, and the target script throws a 'session not found' error.

So to solve this problem, it is possible to make the page inside the IFRAME more trusted: if the inner page sends a P3P header with a privacy policy that is acceptable to IE, the cookies will be accepted. So here is how to do this in Laravel app. Add this header in your laravel controller.

header('P3P: CP="This site does not have a p3p policy."');

And that's it it will solve the problem.

You can get more information about P3P policy from below link.

https://www.w3.org/P3P/details.html


Hope this helps you.