<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Advanced Programming Stories &#187; php</title>
	<atom:link href="http://developstories.gr/cat/php/feed/" rel="self" type="application/rss+xml" />
	<link>http://developstories.gr</link>
	<description>advanced web development techniques &#38; reverse engineering stories</description>
	<lastBuildDate>Sun, 29 Apr 2012 21:44:53 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>Asynchronous multiple file upload με το swfupload</title>
		<link>http://developstories.gr/php/asynchronous-multiple-file-upload-%ce%bc%ce%b5-%cf%84%ce%bf-swfupload/</link>
		<comments>http://developstories.gr/php/asynchronous-multiple-file-upload-%ce%bc%ce%b5-%cf%84%ce%bf-swfupload/#comments</comments>
		<pubDate>Mon, 31 Oct 2011 10:24:06 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[jQuery]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[upload]]></category>

		<guid isPermaLink="false">http://developstories.gr/?p=151</guid>
		<description><![CDATA[Μέχρι σήμερα έχω δοκιμάσει πολλούς τρόπους για ajax file upload και με κανένα δεν ήμουν ποτέ ευχαριστημένος. Ένας από αυτούς τους τρόπους που δοκίμασα, χρειάστηκε ακόμα και η εγκατάσταση του php extension uploadprogress. Σε συνδιασμό με css replace στο input file controll είχα ένα ικανοποιητικό αποτέλεσμα για asynchronous file upload. Τελικά κατέληξα να δουλεύω με [...]]]></description>
			<content:encoded><![CDATA[<p>Μέχρι σήμερα έχω δοκιμάσει πολλούς τρόπους για <a title="10+Ajax Upload File Sample With PHP" href="http://www.freshdesignweb.com/10example-ajax-upload-file-with-php.html" target="_blank">ajax file upload</a> και με κανένα δεν ήμουν ποτέ ευχαριστημένος. Ένας από αυτούς τους τρόπους που δοκίμασα, χρειάστηκε ακόμα και η εγκατάσταση του php extension <a title="Php extension uploadprogress" href="http://t.wits.sg/2008/06/25/howto-php-and-jquery-upload-progress-bar/" target="_blank">uploadprogress</a>. Σε συνδιασμό με <a title="Query Custom File Upload Input" href="http://www.filamentgroup.com/lab/jquery_custom_file_input_book_designing_with_progressive_enhancement/" target="_blank">css replace στο input file controll</a> είχα ένα ικανοποιητικό αποτέλεσμα για asynchronous file upload. Τελικά κατέληξα να δουλεύω με το <a title="Uplodify jQuery plugin" href="http://www.uploadify.com" target="_blank">uplodify</a> ένα jquery plugin χωρίς να μου αρέσει πολύ.</p>
<p>Τον τελευταίο καιρό ασχολήθηκα ξανά με το θέμα και βρήκα ένα πολύ ενδιαφέρων project το <a title="Upload multiple files" href="http://swfupload.org/" target="_blank">swfupload</a>, το οποίο το μόνο του μειονέκτημα είναι ότι δεν είναι jquery plugin. Δεν πειράζει όμως γιατί βρήκα <a title="jQuery plugin that makes working with SWFUpload even easier" href="https://github.com/ifunk/swfupload-jquery-plugin" target="_blank">plugin σε jquery</a> που το κάνει port. To swfupload είναι πολύ κάλο γιατί έχει υποστήριξη για multiple files, filter για τύπο αρχείων (πχ *.pdf), button image replace (hover,disable,&#8230;), και πολύ καλή διαχείριση των events. Η υλοποίηση του είναι σε flash, έτσι υπάρχει πληροφορία κατά το upload ποσά bytes έχουν ανεβεί. Το σημαντικότερο που με ενθουσίασε είναι ότι μπορείς να ελέγξεις πότε θα ξεκινήσει το upload, δηλαδή διαχωρίζει το select file, από το upload file event.</p>
<p>Όλα τα υπόλοιπα που έχω δοκιμάσει, μόλις επιλέξεις ένα αρχείο, ανεβαίνει κατευθείαν στον server, με αποτέλεσμα να πρέπει να αποθήκευσεις το αρχείο κάπου temporarily ώστε μετά την ολοκλήρωση της φόρμας να μπορείς να το χρησιμοποιήσεις. Αυτό χρειάζεται μέθοδο για file garbage collection σε περίπτωση που δεν ολοκληρωθεί η αποστολή της φόρμας για να σβήνει τα άχρηστα αρχεία.</p>
<p>Σε συνδυασμό με το <a title="jQuery Progress Bar plugin" href="http://t.wits.sg/jquery-progress-bar/" target="_blank">jQuery progress bar</a> το swfupload γίνεται το απόλυτο tool για upload files. Ας το δούμε λίγο στην πράξη. Θα φτιάξουμε μια φόρμα, με ένα πεδίο, και με επιλογή για 4 text αρχεία (.txt).</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php
session_start();
?&gt;
&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Transitional//EN&quot; &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quot;&gt;
&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot;&gt;
&lt;head&gt;
&lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=UTF-8&quot; /&gt;
&lt;title&gt;Upload files&lt;/title&gt;
&lt;link href=&quot;main.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;js/jquery.min.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;js/jquery.progressbar.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;js/swfupload.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;js/jquery.swfupload.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot;&gt;var SID=&quot;&lt;?php echo session_id();?&gt;&quot;;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;js/main.js&quot;&gt;&lt;/script&gt;
&lt;/head&gt;

&lt;body&gt;

&lt;form action=&quot;&quot; id=&quot;form&quot; method=&quot;post&quot;&gt;
&lt;fieldset&gt;
&lt;label for=&quot;email&quot;&gt;EMAIL&lt;/label&gt;
&lt;input type=&quot;text&quot; name=&quot;email&quot; id=&quot;email&quot; value=&quot;&quot; /&gt;
&lt;div id=&quot;upload_form&quot;&gt;
Files (max 4):
&lt;div id=&quot;custom-queue&quot;&gt;&lt;/div&gt;
&lt;input id=&quot;btn_file&quot; type=&quot;button&quot; /&gt;
&lt;/div&gt;
&lt;br/&gt;
&lt;div id=&quot;bar_file&quot; style=&quot;display:none&quot;&gt;&lt;/div&gt;
&lt;div id=&quot;ajax_loader&quot; style=&quot;display:none&quot;&gt;&lt;img src=&quot;img/ajax-loader.gif&quot; alt=&quot;loader&quot; /&gt;&lt;/div&gt;
&lt;input id=&quot;submit_btn&quot; type=&quot;submit&quot; value=&quot;Submit&quot;/&gt;
&lt;/fieldset&gt;
&lt;/form&gt;

&lt;/body&gt;
&lt;/html&gt;
</pre>
<p>Στο παραπάνω παράδειγμα χρειάζεται στο php.ini η μεταβλητή session.auto_start off γιατί στην συνέχεια θα χρειαστούμε να περάσουμε στο upload script το session_id, ώστε να έχουμε μια σύνδεση του αποθηκευμένου αρχείου με το submit form script. Η σελίδα μας φορτώνει όλα τα απαραίτητα javascript libs  καθώς και το main.js, όπου εκεί βρίσκετε ο κύριος κώδικας. Η φόρμα μας έχει το &#8220;custom-queue&#8221; div, οπού εκεί θα υποδεχθεί τα επιλεγμένα αρχεία,  το &#8220;btn_file&#8221; button όπου εκεί θα φορτωθεί ο κώδικας του swfupload, και 2 hidden div όπου το 1ο έχει το progress bar για το upload των αρχείων και το 2o έχει ένα <a title="Ajax loading gif animator" href="http://www.ajaxload.info/" target="_blank">ajax loader image</a> το οποίο θα εμφανιστεί κατά την αποστολή της φόρμας.</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php
session_id($_GET['SID']);
session_start();

$dest='upload_files/'.$_GET['SID'].'/';
if (!file_exists($dest)) mkdir($dest);
$dest.=$_FILES['Filedata']['name'];
move_uploaded_file($_FILES['Filedata']['tmp_name'],$dest);
die($_FILES['Filedata']['size']);
?&gt;
</pre>
<p>Αυτό είναι ένα απλό upload script που η μόνη του ιδιαιτερότητα είναι ότι χρησιμοποιεί την μεταβλητή $_GET['SID'] για να ξεκινήσει το ίδιο session και για να αποθυκεύσει το αρχείο σε folder ώστε στην συνέχεια να είναι προσπελάσιμο από το submit form script. Στο παράδειγμά μας κάνει create ένα folder με όνομα το $_GET['SID'], και εκεί μέσα βάζει τα αρχεία από το upload. Όσα αρχεία επιλέγουμε τότε φορές θα εκτελεστεί το upload script. Στο τέλος τυπώνουμε το filezize, ώστε αν κάτι έχει γίνει λάθος το filesize θα είναι 0 και το swfupload θα προκαλέσει error event. Περισσότερα σχετικά με το error handling μπορείτε να δείτε στο <a title="Swfupload documentation" href="http://demo.swfupload.org/Documentation/" target="_blank">manual</a> του swfupload.</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php
session_start();

$ret=array('success'=&gt;true);

// TODO:

header('Cache-Control: no-cache, must-revalidate');
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Content-type: application/json');
echo json_encode($ret);
?&gt;
</pre>
<p>Το submit post form είναι ένα απλό ajax script όπου μπορεί να γυρίσει μεταβλητές σε json, όπως success κτλ. Εδώ χρειάζεται κάποιος επιπλέον κώδικας για να σβήνει τα αρχεία αν δεν ολοκληρωθεί η διαδικασία (είχα αναφέρει παραπάνω για file garbage collection), εδώ όμως όπως βλέπετε είναι ποιο απλή η διαδικασία. Τα αρχεία τώρα μπορούμε να τα βρούμε πολύ εύκολα γιατί όπως είπαμε και παραπάνω τα έχουμε αποθυκεύσει με βάση το session_id.</p>
<pre class="brush: jscript; title: ; notranslate">
$(document).ready(function(){

$(&quot;#upload_form&quot;).swfupload({

upload_url : &quot;upload?SID=&quot;+SID,
flash_url : &quot;swfupload.swf&quot;,

file_size_limit : &quot;10 MB&quot;,
file_upload_limit : &quot;0&quot;,
file_queue_limit: &quot;4&quot;,
file_types: &quot;*.txt&quot;,
file_types_description: &quot;Text files&quot;,

button_image_url : &quot;img/upload.png&quot;,
button_width : 88,
button_height : 22,
button_placeholder : $(&quot;#btn_file&quot;)[0],
button_window_mode : SWFUpload.WINDOW_MODE.TRANSPARENT

})
.bind(&quot;fileQueued&quot;, function(event, file){
$(&quot;#custom-queue&quot;).append('&lt;div id=&quot;file_'+file.id+'&quot; title=&quot;'+file.name+
'&quot;&gt;'+file.name+'&lt;span&gt; (&lt;a title=&quot;remove file&quot; onclick=&quot;return removeFile(\''+file.id+'\')&quot; href=&quot;#remove&quot;&gt;x&lt;/a&gt;)&lt;/span&gt;&lt;/div&gt;');
})
.bind('uploadComplete', function(event, file){
// upload has completed, lets try the next one in the queue
$(&quot;#file_&quot;+file.id).removeClass('file-progress').addClass('file-done');
if ($('.file-queue').length==$('.file-done').length) {
$(&quot;#bar_file&quot;).hide();
$(&quot;#ajax_loader&quot;).show();

$.ajax({
type: &quot;POST&quot;,
url: &quot;submit.php&quot;,
data: $(&quot;#form&quot;).serialize(),
dataType: &quot;json&quot;,
success: function(data) {
$(&quot;#ajax_loader&quot;).fadeOut();
$(&quot;#bar_file&quot;).html('&lt;strong&gt;Submit completed&lt;/strong&gt;').fadeIn();
}
});
}
else {
$(this).swfupload('startUpload');
}
})
.bind(&quot;uploadStart&quot;, function(event, file){
$(&quot;#file_&quot;+file.id).addClass('file-progress');
$(&quot;#bar_file&quot;).progressBar(0);
})
.bind(&quot;uploadProgress&quot;, function(event, file, bytesLoaded, bytesTotal){
var percentage = Math.floor(100 * parseInt(bytesLoaded) / parseInt(bytesTotal));
$(&quot;#bar_file&quot;).progressBar(percentage);
})
.bind(&quot;uploadError&quot;, function(event, file, errorCode, message){
if (errorCode === SWFUpload.UPLOAD_ERROR.FILE_CANCELLED) {
$(&quot;#file_&quot;+file.id).fadeOut('normal',function() { $(&quot;#file_&quot;+file.id).remove(); });
}
});

$(&quot;#bar_file&quot;).progressBar({
boxImage : 'img/progressbar.gif',
barImage : 'img/progressbg_orange.gif'
});

$(&quot;#form&quot;).submit(function() {
if ($('.file-queue').length==0) {
alert('You must select a file!');
}
else {
$(&quot;#bar_file&quot;).show();
$(&quot;#submit_btn&quot;).hide();
$(&quot;#SWFUpload_0&quot;).width(0);
$(&quot;#upload_form&quot;).swfupload('startUpload');
}
return false;
});
});

function removeFile(id) {
$(&quot;#upload_form&quot;).swfupload('cancelUpload',id,true);
return false;
}
</pre>
<p>Και πάμε στο σημαντικότερο μέρος του project που είναι javascript. Εδώ έχουμε όλα τα bind events για το swfupload, από το load, το select files μέχρι και το submit της φόρμας. Ας τα πάρουμε από την αρχή για να τα δούμε αναλυτικά.</p>
<pre class="brush: jscript; title: ; notranslate">
$(&quot;#upload_form&quot;).swfupload({

upload_url : &quot;upload?SID=&quot;+SID,
flash_url : &quot;swfupload.swf&quot;,

file_size_limit : &quot;10 MB&quot;,
file_upload_limit : &quot;0&quot;,
file_queue_limit: &quot;4&quot;,
file_types: &quot;*.txt&quot;,
file_types_description: &quot;Text files&quot;,

button_image_url : &quot;img/upload.png&quot;,
button_width : 88,
button_height : 22,
button_placeholder : $(&quot;#btn_file&quot;)[0],
button_window_mode : SWFUpload.WINDOW_MODE.TRANSPARENT

})
</pre>
<p>Εδώ φορτώνουμε το swfupload βάζοντας το url από το upload.php (περνάμε και το SID που το έχουμε βάλει σε μια javascript μεταβλητή και περιέχει το session_id, το url που βρίσκεται το swfupload.swf, το μέχρι πόσα αρχεία θέλουμε, τι μέγεθος να έχει το καθένα, και τι τύπο (πχ μπορούμε να βάλουμε &#8220;*.pdf,*.odt&#8221;).  Τέλος το image αρχείο, με το μέγεθος του και σε ποιο element να γίνει bind.</p>
<pre class="brush: jscript; title: ; notranslate">
.bind(&quot;fileQueued&quot;, function(event, file){
$(&quot;#custom-queue&quot;).append('&lt;div id=&quot;file_'+file.id+'&quot; title=&quot;'+file.name+
'&quot;&gt;'+file.name+'&lt;span&gt; (&lt;a title=&quot;remove file&quot; onclick=&quot;return removeFile(\''+file.id+'\')&quot; href=&quot;#remove&quot;&gt;x&lt;/a&gt;)&lt;/span&gt;&lt;/div&gt;');
})
</pre>
<p>Και κάπου εδώ αρχίζουν τα events, 1ο event το &#8220;fileQueued&#8221;, το οποίο εκτελείτε κατά την επιλογή αρχείων. Όσα αρχεία επιλεγούν τόσες φορές θα εκτελεστεί. Εδώ το μόνο που θέλουμε να κάνουμε είναι να εμφανίσουμε τα επιλεγμένα αρχεία, στο div &#8220;custom-queue&#8221;.  Τέλος βάζουμε και ένα (x) για αφαίρεσή αρχείου από την λίστα.  Για την αφαίρεσή χρειαζόμαστε το file.id.  Στο file.name έχουμε το όνομα του αρχείου.</p>
<pre class="brush: jscript; title: ; notranslate">
.bind(&quot;uploadStart&quot;, function(event, file){
$(&quot;#file_&quot;+file.id).addClass('file-progress');
$(&quot;#bar_file&quot;).progressBar(0);
})
.bind(&quot;uploadProgress&quot;, function(event, file, bytesLoaded, bytesTotal){
var percentage = Math.floor(100 * parseInt(bytesLoaded) / parseInt(bytesTotal));
$(&quot;#bar_file&quot;).progressBar(percentage);
})
.bind(&quot;uploadError&quot;, function(event, file, errorCode, message){
if (errorCode === SWFUpload.UPLOAD_ERROR.FILE_CANCELLED) {
$(&quot;#file_&quot;+file.id).fadeOut('normal',function() { $(&quot;#file_&quot;+file.id).remove(); });
}
});
</pre>
<p>Τα επόμενα 3 event έχουν να κάνουν με το upload. Στο &#8220;uploadStart&#8221; αλάζουμε το class στο αρχείο που είναι να ανέβει ώστε να φαίνεται ποιο είναι, και μηδενίζουμε το progress bar. Και αυτό το event εκτελείτε τόσες φορές όσα τα αρχεία που έχουμε επιλέξει. To &#8220;uploadProgress&#8221; μας δείχνει το progress του upload. Τέλος το &#8220;uploadError&#8221; εκτελείτε σε περίπτωση σφάλματος. Εδώ το χρησιμοποιούμε και για την αφαίρεση ενός αρχείου από την λίστα.</p>
<pre class="brush: jscript; title: ; notranslate">
.bind('uploadComplete', function(event, file){
// upload has completed, lets try the next one in the queue
$(&quot;#file_&quot;+file.id).removeClass('file-progress').addClass('file-done');
if ($('.file-queue').length==$('.file-done').length) {
$(&quot;#bar_file&quot;).hide();
$(&quot;#ajax_loader&quot;).show();

$.ajax({
type: &quot;POST&quot;,
url: &quot;submit.php&quot;,
data: $(&quot;#form&quot;).serialize(),
dataType: &quot;json&quot;,
success: function(data) {
$(&quot;#ajax_loader&quot;).fadeOut();
$(&quot;#bar_file&quot;).html('&lt;strong&gt;Submit completed&lt;/strong&gt;').fadeIn();
}
});
}
else {
$(this).swfupload('startUpload');
}
})
</pre>
<p>Το &#8220;uploadComplete&#8221; είναι το event που εκτελείτε μετά την ολοκλήρωση του upload κάθε αρχείου.  Εδώ ελέγχουμε και αν έχει άλλο δίνουμε εντολή για το επόμενο, κ.ο.κ. Αν δεν έχει άλλο κάνουμε submit την φόρμα μας. Για τον έλεγχο αν υπάρχει άλλο αρχείο στην λίστα, χρησιμοποιούμε την class  &#8220;file-done&#8221; την οποία την προσθέτουμε στο div &#8220;file-queue&#8221; μετά το τέλος του upload. Οπότε με ένα απλό έλεγχο στο length του &#8220;file-queue&#8221; και του &#8220;file-done&#8221;, αν είναι ίσα δηλαδή, δεν έχουμε άλλα αρχεία.</p>
<pre class="brush: jscript; title: ; notranslate">
$(&quot;#form&quot;).submit(function() {
if ($('.file-queue').length==0) {
alert('You must select a file!');
}
else {
$(&quot;#bar_file&quot;).show();
$(&quot;#submit_btn&quot;).hide();
$(&quot;#SWFUpload_0&quot;).width(0);
$(&quot;#upload_form&quot;).swfupload('startUpload');
}
return false;
});
</pre>
<p>Τέλος αλλάζουμε το submit event της φόρμας ώστε να γίνεται πρώτα το upload. Δίνουμε στο swfupload object width 0, για να εξαφανιστεί το κουμπί upload, κάνουμε hide το submit button, εμφανίζουμε το progress bar και ξεκινάμε το 1o upload, δίνοντάς εντολή στο flash.</p>
<p>Αυτό ήταν ένα απλό παράδειγμα σε σχέση με τις δυνατότητες που παρέχει το swfupload, το οποίο σε συνδυασμό και με άλλα jquery plugins, το αποτέλεσμα μπορεί να είναι καλύτερο.</p>
<p>Όλος ο παραπάνω κώδικας βρίσκεται <a title="Download swfupload.zip" href="http://developstories.gr/wp-content/uploads/swfupload.zip">εδώ και μπορείτε να το κατεβάσατε ελεύθερα</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://developstories.gr/php/asynchronous-multiple-file-upload-%ce%bc%ce%b5-%cf%84%ce%bf-swfupload/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Reverse WordPress admin module</title>
		<link>http://developstories.gr/php/reverse-wordpress-admin-module/</link>
		<comments>http://developstories.gr/php/reverse-wordpress-admin-module/#comments</comments>
		<pubDate>Mon, 14 Feb 2011 00:59:51 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[Reverse Engineering]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://developstories.gr/?p=147</guid>
		<description><![CDATA[Αυτό που με εξιτάρει περισσότερο στο τομέα του development είναι όταν έχω ένα πρόβλημα και η λύση είναι στο reverse Ας υποθέσουμε ότι χρειαζόμαστε να συνδέσουμε μια υπάρχουσα εφαρμογή με το wordpress χωρίς όμως να ξαναφτιάξουμε την εφαρμογή χρησιμοποιώντας τις βιβλιοθήκες του. Χρειαζόμαστε ένα plugin που να εμφανίζει ένα iframe με την εφαρμογή μας. Πολύ [...]]]></description>
			<content:encoded><![CDATA[<p>Αυτό που με εξιτάρει περισσότερο στο τομέα του development είναι όταν έχω ένα πρόβλημα και η λύση είναι στο reverse <img src='http://developstories.gr/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>Ας υποθέσουμε ότι χρειαζόμαστε να συνδέσουμε μια υπάρχουσα εφαρμογή με το <a href="http://wordpress.org/">wordpress</a> χωρίς όμως να ξαναφτιάξουμε την εφαρμογή χρησιμοποιώντας τις βιβλιοθήκες του. Χρειαζόμαστε ένα <a href="http://codex.wordpress.org/Plugin_Resources">plugin</a> που να εμφανίζει ένα iframe με την εφαρμογή μας. Πολύ εύκολο για κάποιον που έχει ασχοληθεί με plugins στο wordpress. Το δύσκολο είναι πως θα καταλάβει η εφαρμογή, ότι ο χρήστης είναι συνδεμένος, ώστε να μην μπορεί κάποιος να την χρησιμοποιήσει χωρίς login. </p>
<p>Και κάπου εδώ ξεκινάει το reverse. Στα php application (open source), σε αντίθεση με τα executable application το reverse είναι πολύ απλή υπόθεση, γιατί το μόνο που χρειάζεται είναι υπομονή και πολλά echo ή file_put_contents.</p>
<p>Ξεκινώντας από την index.php στο wp-admin έχουμε ένα include στην admin.php όπου στην συνέχεια έχει μια κλήση στην function auth_redirect που βρίσκεται στην  wp-includes/ pluggable.php. Στην function auth_redirect έχει μια κλήση στην wp_validate_auth_cookie όπου εκεί βρίσκεται ο έλεγχος για την εγκυρότητα του logged in. Ο έλεγχος βασίζεται σε ένα cookie όπου περιέχει 3 στοιχεία, το username το expires, και τέλος ένα hash value. Με κάποιο αλγόριθμο χρησιμοποιώντας το username κάποια salt και keys, και το encrypted password που έχει o user αποθηκευμένο στην db (mysql), παράγεται ένα hash value το οποίο στην συνέχεια συγκρίνεται με το hast value από το cookie.</p>
<p>Άρα χρειαζόμαστε 2 τιμές για να μπορέσουμε να κάνουμε την σύγκριση και στον δικό μας κώδικα. Η μία είναι το cookie και η δεύτερη η πρόσβαση στην db για να διαβάσουμε το encrypted password. Το cookie μπορούμε να το περάσουμε σαν argument στο iframe και το password μπορούμε να το διαβάσουμε αν γνωρίζουμε τα login/pass της mysql (connection string) και το username του χρήστη. </p>
<p>Φτιάχνουμε λοιπόν ένα plugin που το μόνο που έχει, είναι την εμφάνιση του iframe στην επιλογή ενός item menu. </p>
<pre class="brush: plain; title: ; notranslate">&lt;?php
/**
 * @package MyAdmin
 */
/*
Plugin Name: MyAdmin
Plugin URI: http://developstories.gr
Description:
Version: 1.0.0
Author: Thek
Author URI: http://socialwhale.com/thek27
License: GPLv2
*/
add_action('admin_menu', 'my_plugin_menu');

function my_plugin_menu() {
	add_menu_page('MyAdmin', MyAdmin', 'read', 'my_menu','my_view');
}

function my_view() {
	echo '&lt;iframe src=&quot;/my-admin?auth_cookie='.$_COOKIE[AUTH_COOKIE].'&amp;auth_key='.urlencode(base64_encode(AUTH_KEY.AUTH_SALT)).'&quot; width=&quot;100%&quot; height=&quot;500&quot;&gt;&lt;/iframe&gt;';
}
?&gt;
</pre>
<p>Αν δούμε καλύτερα στο src του iframe περνάμε 2 μεταβλητές και όχι μόνο το cookie άλλα το AUTH_KEY και το AUTH_SALT όπου τα χρησιμοποιεί ο αλγόριθμος για την παραγωγή του hash value. Αυτά βρίσκονται στο wp-config.php. Για μεγαλύτερη ασφάλεια μπορούμε να τα κάνουμε copy/paste στον δικό μας αλγόριθμο χωρίς να τα περνάμε στο url. </p>
<p>Τώρα δεν μένει παρά να αντιγράψουμε τον κώδικα που παράγει το hast value, και στην συνεχεία να κάνουμε την σύγκριση.<br />
Ο αλγόριθμος είναι βασισμένος σε 2 συνεχόμενα md5 hash values. </p>
<pre class="brush: plain; title: ; notranslate">&lt;?
list($username, $expiration, $hmac) = explode('|', $_GET['auth_cookie']);

$db-&gt;query('SELECT `user_pass` FROM `wp_users` WHERE `user_login`=&quot;'.addslashes($username).'&quot; LIMIT 1');
if ($db-&gt;next()) {
	$pass_frag = substr($db-&gt;Record['user_pass'], 8, 4);
	$key = hash_hmac('md5', $username . $pass_frag . '|' . $expiration, base64_decode($_GET['auth_key']));
	$hash = hash_hmac('md5', $username . '|' . $expiration, $key);

	//$hash==$hmac
}
?&gt;</pre>
]]></content:encoded>
			<wfw:commentRss>http://developstories.gr/php/reverse-wordpress-admin-module/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ζητούνται Web developers</title>
		<link>http://developstories.gr/uncategorized/%ce%b6%ce%b7%cf%84%ce%bf%cf%8d%ce%bd%cf%84%ce%b1%ce%b9-web-developers/</link>
		<comments>http://developstories.gr/uncategorized/%ce%b6%ce%b7%cf%84%ce%bf%cf%8d%ce%bd%cf%84%ce%b1%ce%b9-web-developers/#comments</comments>
		<pubDate>Fri, 25 Sep 2009 17:32:27 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[web developers]]></category>
		<category><![CDATA[εργασία]]></category>

		<guid isPermaLink="false">http://developstories.gr/?p=91</guid>
		<description><![CDATA[Αν είστε subscriber στο blog μου σίγουρα θα σας ενδιαφέρει η παρακάτω αγγελία. Η αγγελία αφορά το Social Whale, το project με το οποίο ασχολούμαι τους τελευταίους μήνες.]]></description>
			<content:encoded><![CDATA[<p>Αν είστε subscriber στο blog μου σίγουρα <a href="http://humanworks.gr/humanworks/%CE%B6%CE%B7%CF%84%CE%BF%CF%8D%CE%BD%CF%84%CE%B1%CE%B9-web-developers/">θα σας ενδιαφέρει η παρακάτω αγγελία</a>. Η αγγελία αφορά το Social Whale, το project με το οποίο ασχολούμαι τους τελευταίους μήνες.</p>
]]></content:encoded>
			<wfw:commentRss>http://developstories.gr/uncategorized/%ce%b6%ce%b7%cf%84%ce%bf%cf%8d%ce%bd%cf%84%ce%b1%ce%b9-web-developers/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>php και sudo</title>
		<link>http://developstories.gr/php/php-%ce%ba%ce%b1%ce%b9-sudo/</link>
		<comments>http://developstories.gr/php/php-%ce%ba%ce%b1%ce%b9-sudo/#comments</comments>
		<pubDate>Fri, 06 Feb 2009 11:34:19 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[sudo]]></category>

		<guid isPermaLink="false">http://developstories.gr/?p=80</guid>
		<description><![CDATA[Ένα απο τα ζητήματα που προκύπτουν στο advanced web development είναι η αλληλεπίδραση με το λειτουργικό σύστημα. Για παράδειγμα θέλουμε να τρέξουμε μία εντολή και να δούμε το αποτέλεσμά της. Αυτό γίνεται εύκολα με την shell_exec() ή την exec() ωστόσο απο μόνη της δέν λύνει όλα τα προβλήματα. Ο apache αλλα και κάθε web server [...]]]></description>
			<content:encoded><![CDATA[<p>Ένα απο τα ζητήματα που προκύπτουν στο advanced web development είναι η αλληλεπίδραση με το λειτουργικό σύστημα. Για παράδειγμα θέλουμε να τρέξουμε μία εντολή και να δούμε το αποτέλεσμά της. Αυτό γίνεται εύκολα με την shell_exec() ή την exec() ωστόσο απο μόνη της δέν λύνει όλα τα προβλήματα.</p>
<p>Ο apache αλλα και κάθε web server τρέχει με ελάχιστα δικαιώματα που συνήθως του επιτρέπουν να κάνει μόνο βασικά πράγματα. Απο άποψη ασφάλειας αυτό είναι θεμιτό και σε καμία περίπτωση δέν πρέπει να τρέχει με δικαιώματα root γιατί εκεί ένα απλό bug ασφαλείας μπορεί να οδηγήσει σε πλήρη καταστροφή. Την λύση σ&#8217;αυτό το πρόβλημα την δίνει το εργαλείο sudo.</p>
<h3>Τί είναι το sudo</h3>
<p>Το <a href="http://www.courtesan.com/sudo/">sudo</a> είναι ένα εργαλείο για *nix συστήματα (unix,linux,κτλ) το οποίο επιτρέπει να τρέξουμε κάποια εντολή με δικαιώματα root. Έτσι αντί να κάνουμε vurnerable όλο τον web server μπορούμε όποτε χρειάζεται να τρέχουμε μέσω sudo τις εντολές που θέλουμε.</p>
<h3>Sudo configuration</h3>
<p>Καταρχήν πρέπει να κάνουμε ένα απλό configuration στο sudo ωστε να δέχεται εντολές απο τον web server. Για την ακρίβεια πρέπει να δώσουμε δικαιώματα στον χρήστη που τρέχει τον apache που συνήθως λέγεται apache. Για σιγουριά δείτε στο httpd.conf το directive User.</p>
<p>Για να κάνουμε το sudo να δέχεται εντολές απο τον web server πάμε στο αρχείο /etc/sudoers και προσθέτουμε την παρακάτω γραμμή:</p>
<blockquote><p><code><strong>apache ALL=(ALL) ALL</strong></code></p></blockquote>
<p>Αν ο χρήστης δέν ονομάζεται apache αντικαταστήστε το όνομα apache στο παραπάνω. Για να μήν υπάρχουν προβλήματα ασφαλείας θέτουμε και ένα password στον χρήστη apache. Αυτό γίνεται απο κονσόλα με την παρακάτω εντολή:</p>
<blockquote><p><strong><code>passwd apache</code></strong></p></blockquote>
<p>Αν δέν ακολουθήσετε το τελευταίο βήμα, κάθε php script στον server θα μπορεί να τρέξει εντολές με δικαιώματα root και αυτό μπορεί να οδηγήσει σε σοβαρά προβλήματα ασφαλείας.</p>
<h3>Τρέχοντας sudo με php</h3>
<p>Αφού τελειώσουμε με τα configuration το υπόλοιπο είναι πολύ εύκολο αρκεί να χρησιμοποιήσετε την παρακάτω <a href="http://developstories.gr/cat/php/">php</a> function που δημιούργησα για αυτό τον σκοπό:</p>
<pre class="brush: php; title: ; notranslate">

define(&quot;SUDO&quot;,&quot;/usr/bin/sudo&quot;);
define(&quot;SUDO_PASS&quot;,&quot;pass&quot;);

// SUDO START
exec('echo '.SUDO_PASS.'|'.SUDO.' -S -v 2&gt;&amp;1');

// SUDO EXECUTE
echo exec(SUDO . &quot; ls /root 2&gt;&amp;1&quot;);

// SUDO STOP
exec(SUDO.&quot; -k 2&gt;&amp;1&quot;);
</pre>
<p>Προσέξτε τα δύο define στην αρχή. Το πρώτο είναι το path για την sudo και λογικά δέν χρειάζεται να το πειράξετε. Το δεύτερο όρισμα (SUDO_PASS) πρέπει να περιέχει το password του apache.</p>
]]></content:encoded>
			<wfw:commentRss>http://developstories.gr/php/php-%ce%ba%ce%b1%ce%b9-sudo/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Hacking php</title>
		<link>http://developstories.gr/php/hacking-php/</link>
		<comments>http://developstories.gr/php/hacking-php/#comments</comments>
		<pubDate>Mon, 02 Feb 2009 11:31:07 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[Reverse Engineering]]></category>
		<category><![CDATA[encryption]]></category>
		<category><![CDATA[hack]]></category>
		<category><![CDATA[hacking]]></category>

		<guid isPermaLink="false">http://developstories.gr/?p=73</guid>
		<description><![CDATA[Όταν τελείωσα το Reverse Engineering Academy course &#8211; και σαν καλός μαθητής που είμουν &#8211; μου έγινε η πρόταση να δημιουργήσω ένα project για την REA 2. Φυσικά λόγω του κολλήματος που έχω με την php σκέφτηκα να γράψω μία encrypted έκδοση της βιβλιοθήκης της php στα windows (php4ts.dll) Φυσικά θα ήταν πιό εύκολο να [...]]]></description>
			<content:encoded><![CDATA[<p>Όταν τελείωσα το <a href="http://developstories.gr/reverse-engineering/reverse-engineering-academy/">Reverse Engineering Academy</a> course &#8211; και σαν καλός μαθητής που είμουν &#8211; μου έγινε η πρόταση να δημιουργήσω ένα project για την REA 2. Φυσικά λόγω του κολλήματος που έχω με την <a href="http://www.php.net/">php</a> σκέφτηκα να γράψω μία encrypted έκδοση της βιβλιοθήκης της php στα windows (php4ts.dll)</p>
<p>Φυσικά θα ήταν πιό εύκολο να χρησιμοποιήσω ένα έτοιμο encryption library, ωστόσο έτσι δέν νομίζω οτι μαθαίνεις αρκετά και δεδομένου οτι μιλάμε για ένα project &#8220;ελεύθερου χρόνου&#8221; άξιζε τον κόπο. Επίσης η όλη εμπειρία που αποκόμισα με βοήθησε στην δημιουργία του php encryption που χρησιμοποιούμε στην <a href="http://www.netwerk.gr/">NetWerk</a> για διάφορα projects που χρειάζεται encryption.</p>
<p>Τελικά το project δέν μπήκε στην REA 2 και για κακή μου τύχη έχασα όλα τα sources αφού χάθηκαν τα backup και μου κλέψαν το laptop! Ευτυχώς ο zero (admin στην REA) είχε κρατήσει ένα αντίγραφο και μου το έστειλε.</p>
<p>Όσοι λοιπόν θέλετε να εξασκηθείτε στο hacking μπορείτε να κατεβάσετε το <a href="http://developstories.gr/wp-content/uploads/php.zip">zipάκι απο εδώ</a> και να παίξετε με το project. Ενδεχομένως  να σας φανούν χρήσιμα και τα εργαλεία για <a href="http://developstories.gr/php/10-must-%CE%B5%CF%81%CE%B3%CE%B1%CE%BB%CE%B5%CE%AF%CE%B1-%CE%B3%CE%B9%CE%B1-reverse-engineering/">reverse engineering</a> που έχω γράψει παλιότερα.</p>
<p>Αν βρείτε λύση &#8211; δηλαδή αν βρείτε τα arguments που χρειάζεται το πρόγραμμα για να καταλάβει πως είστε &#8220;php master&#8221; &#8211; αφήστε ένα σχόλιο. Happy cracking <img src='http://developstories.gr/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://developstories.gr/php/hacking-php/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP ping</title>
		<link>http://developstories.gr/php/php-ping/</link>
		<comments>http://developstories.gr/php/php-ping/#comments</comments>
		<pubDate>Fri, 30 Jan 2009 10:31:50 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[php ping]]></category>
		<category><![CDATA[ping]]></category>

		<guid isPermaLink="false">http://developstories.gr/?p=70</guid>
		<description><![CDATA[Σε ένα απο τα τελευταία projects που ασχολούμαι στην NetWerk, η εφαρμογή μου επικοινωνεί με web services που βρίσκονται σε άλλους servers, ωστόσο για την αποφυγή λαθών και για καλύτερο debugging ήθελα να κάνω ping τον server που &#8220;μιλάω&#8221; ωστε να ξέρω τι συμβαίνει. Πώς κάνουμε ping με php Επειδή γενικώς δέν μου αρέσει να [...]]]></description>
			<content:encoded><![CDATA[<p>Σε ένα απο τα τελευταία projects που ασχολούμαι στην <a href="http://www.netwerk.gr/">NetWerk</a>, η εφαρμογή μου επικοινωνεί με web services που βρίσκονται σε άλλους servers, ωστόσο για την αποφυγή λαθών και για καλύτερο debugging ήθελα να κάνω ping τον server που &#8220;μιλάω&#8221; ωστε να ξέρω τι συμβαίνει.</p>
<h3>Πώς κάνουμε ping με php</h3>
<p>Επειδή γενικώς δέν μου αρέσει να ανακαλύπτω τον τροχό κάθε φορά που κάνω κάτι καινούριο, έψαξα στο internet και ανακάλυψα ένα code snippet για <a href="http://birk-jensen.dk/articles/php/ping/ping.php">ping μέσω php</a>. Το μόνο πρόβλημα, είναι πως εφόσον o server που κάνουμε ping δέν απαντήσει, το scriptάκι κολλάει. Παρακάτω είναι μία αλλαγμένη έκδοση του snippet οπου ορίζεις το timeout.</p>
<pre class="brush: php; title: ; notranslate">

&lt;?php

//add
function microtime_float() {
list($usec, $sec) = explode(&quot; &quot;, microtime());
return ((float)$usec + (float)$sec);
}

// Checksum calculation function
function icmpChecksum($data) {
if (strlen($data)%2)
$data .= &quot;\x00&quot;;

$bit = unpack('n*', $data);
$sum = array_sum($bit);

while ($sum &gt;&gt; 16)
$sum = ($sum &gt;&gt; 16) + ($sum &amp;amp; 0xffff);

return pack('n*', ~$sum);
}

// Making the package
$type= &quot;\x08&quot;;
$code= &quot;\x00&quot;;
$checksum= &quot;\x00\x00&quot;;
$identifier = &quot;\x00\x00&quot;;
$seqNumber = &quot;\x00\x00&quot;;
$data= &quot;Scarface&quot;;
$package = $type.$code.$checksum.$identifier.$seqNumber.$data;
$checksum = icmpChecksum($package); // Calculate the checksum
$package = $type.$code.$checksum.$identifier.$seqNumber.$data;
// And off to the sockets
$socket = socket_create(AF_INET, SOCK_RAW, 1);
if (socket_connect($socket, $argv[1], null)) {

socket_set_option($socket,SOL_SOCKET, SO_RCVTIMEO, array(&quot;sec&quot;=&gt;5, &quot;usec&quot;=&gt;0)); // thek add

// If you're using below PHP 5, see the manual for the microtime_float
// function. Instead of just using the m
//     icrotime() function.

//$startTime = microtime(true); // thek remove
$startTime = microtime_float(); // thek add

socket_send($socket, $package, strLen($package), 0);
if (socket_read($socket, 255)) {
//echo round(microtime(true) - $startTime, 4) .' seconds'; // thek remove
echo round(microtime_float() - $startTime, 4) .' seconds'; // thek add
}
else {
echo 'lost connection';
}
socket_close($socket);
}
else {
echo 'lost connection';
}
?&gt;
</pre>
<p>Στο παραπάνω παράδειγμα το timeout θα γίνει σε 5 δευτερόλεπτα. Αν θέλετε να το αλλάξετε απλώς αλλάξτε το 5 στην παρακάτω γραμμή:</p>
<p>socket_set_option($socket,SOL_SOCKET, SO_RCVTIMEO, array(&#8220;sec&#8221;=&gt;5, &#8220;usec&#8221;=&gt;0)); // thek add</p>
<p>Το script τρέχει μόνο απο CLI δίνοντας την εντολή</p>
<p>php -q script.php &lt;ip address&gt;</p>
<p>όπου script.php είναι το παρών σκριπτάκι και &lt;ip_address&gt; είναι η διεύθυνση που θέλετε να κάνετε ping. Σε επόμενο άρθρο θα γράψω πώς να το κάνετε απο web εφαρμογή.</p>
]]></content:encoded>
			<wfw:commentRss>http://developstories.gr/php/php-ping/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Google trace script</title>
		<link>http://developstories.gr/php/google-trace-script/</link>
		<comments>http://developstories.gr/php/google-trace-script/#comments</comments>
		<pubDate>Mon, 26 Jan 2009 11:18:16 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[nuSOAP]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[seo]]></category>
		<category><![CDATA[google]]></category>
		<category><![CDATA[search engine optimization]]></category>

		<guid isPermaLink="false">http://developstories.gr/?p=64</guid>
		<description><![CDATA[Ένα απο τα θέματα που μας ενδιαφέρουν σχετικά με το search engine optimization, είναι το κάθε πότε κάνει crawl το google το site μας. Ειδικότερα θέλουμε να δούμε &#8211; κυρίως για εγκυκλοπαιδικούς λόγους &#8211; πόσος καιρός μεσολαβεί απο ένα crawl μέχρι την παρουσία μιας σελίδας στο index. Με αυτές τις απορίες κατά νου αποφασίσαμε να [...]]]></description>
			<content:encoded><![CDATA[<p>Ένα απο τα θέματα που μας ενδιαφέρουν σχετικά με το <a href="http://developstories.gr/cat/seo/">search engine optimization</a>, είναι το κάθε πότε κάνει crawl το google το site μας. Ειδικότερα θέλουμε να δούμε &#8211; κυρίως για εγκυκλοπαιδικούς λόγους &#8211; πόσος καιρός μεσολαβεί απο ένα crawl μέχρι την παρουσία μιας σελίδας στο index.</p>
<p>Με αυτές τις απορίες κατά νου αποφασίσαμε να δημιουργήσουμε ένα απλό scriptάκι το οποίο απλά καταγράφει κάθε valid request του google. To script είναι πάρα πολύ απλό, ωστόσο ελπίζω να σας χρησιμέψει.</p>
<h3>Το Google script</h3>
<p>Καταρχήν χρειαζόμαστε ένα mysql database που θα κρατάει τα δεδομένα μας. Στην προκειμένη περίπτωση δημιουργήσαμε ένα database με όνομα &#8220;google_spy&#8221; και τρέξαμε το παρακάτω SQL για να δημιουργηθεί ο πίνακας που θα κρατάει τα δεδομένα:</p>
<pre class="brush: sql; title: ; notranslate">
CREATE TABLE IF NOT EXISTS `trace` (
  `TraceID` int(10) unsigned NOT NULL auto_increment,
  `Domain` varchar(100) NOT NULL default '',
  `Time` datetime NOT NULL default '0000-00-00 00:00:00',
  `Bot` varchar(100) NOT NULL default '',
  `Url` text NOT NULL,
  PRIMARY KEY  (`TraceID`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
</pre>
<p>Παρακάτω είναι το php script που κάνει την δουλειά:</p>
<pre class="brush: php; title: ; notranslate">
&lt;?
php
define ('GOOGLE_AGENT','Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)');

//A few settings for the script:

$db_host = 'localhost';

$db_user = 'user';

$db_pass = 'password';

function googlebot($ip)  {

  $bot = 'googlebot.com';

  $name = gethostbyaddr($ip);

  if ($name == $ip) return false;

  return (strpos($name, $bot) !== false and gethostbyname($name) == $ip) ? true : false;

}

if ($_SERVER['HTTP_USER_AGENT']==GOOGLE_AGENT &amp;amp;amp;amp;&amp;amp;amp;amp; googlebot($_SERVER['REMOTE_ADDR'])) 

{

	$url='http://'.$_SERVER['HTTP_HOST'];

	if ($_SERVER['REQUEST_URI']) $url.=$_SERVER['REQUEST_URI'];

	$url_u8=iconv('Windows-1253','UTF-8',$url);

	if (crc32($url)==crc32(iconv('UTF-8','Windows-1253',$url_u8))) $url=$url_u8;

	$url=urldecode($url);

	$sql =&quot;INSERT LOW_PRIORITY INTO `google_spy`.`trace` SET `Domain`='&quot;.$_SERVER['HTTP_HOST'].&quot;',`Time`='&quot;.date('Y-m-d H:i:s').&quot;',&quot;;

	$sql.=&quot;`Bot`='&quot;.gethostbyaddr($_SERVER['REMOTE_ADDR']).&quot;',`Port`='&quot;.$_SERVER['REMOTE_PORT'].&quot;',`Url`='$url'&quot;;

	$con=mysql_connect($db_host,$db_user,$db_pass);

	mysql_query(&quot;SET NAMES 'utf8'&quot;,$con);

	mysql_query($sql,$con);

	mysql_close($con);

}

?&gt;
</pre>
<p>Για να το χρησιμοποιείσετε απλώς αλλάξτε τα settings στην αρχή ($db_host, $db_user, $db_pass) και κάντε include το script σε οποιοδήποτε site θέλετε να κρατάτε logs. Σημειώστε οτι το script κρατάει μία εγγραφή ανα visit (που προέρχεται απο το google) οπότε καλό θα είναι να σβήνετε τα δεδομένα ανα τακτά χρονικά διαστήματα.</p>
<p>Αν κάνετε κάποια μετατροπή ή δημιουργήσετε ένα όμορφο interface για το scriptάκι μήν διστάσετε να το μοιραστείτε μαζί μας <img src='http://developstories.gr/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://developstories.gr/php/google-trace-script/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>10 must εργαλεία για reverse engineering</title>
		<link>http://developstories.gr/php/10-must-%ce%b5%cf%81%ce%b3%ce%b1%ce%bb%ce%b5%ce%af%ce%b1-%ce%b3%ce%b9%ce%b1-reverse-engineering/</link>
		<comments>http://developstories.gr/php/10-must-%ce%b5%cf%81%ce%b3%ce%b1%ce%bb%ce%b5%ce%af%ce%b1-%ce%b3%ce%b9%ce%b1-reverse-engineering/#comments</comments>
		<pubDate>Wed, 17 Dec 2008 14:22:41 +0000</pubDate>
		<dc:creator>Kostas Theodorou</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[Reverse Engineering]]></category>
		<category><![CDATA[hack]]></category>

		<guid isPermaLink="false">http://developstories.gr/?p=39</guid>
		<description><![CDATA[Παρακάτω είναι μια λίστα με διάφορα εργαλεία για reverse engineering που μπορείτε να χρησιμοποιήσετε αν ασχολείστε με το &#8220;σπόρ&#8221;. Servant Salamander Το Servant Salamander είναι ένα φανταστικό εργαλείο γενικά για development αλλα και για απλούς χρήστες. Το salamander είναι ένας file manager που θυμίζει λίγο το παλιό norton commander, ωστόσο παρέχει αρκετές ευκολίες για τους [...]]]></description>
			<content:encoded><![CDATA[<p>Παρακάτω είναι μια λίστα με διάφορα εργαλεία για <a href="http://developstories.gr/cat/reverse-engineering/">reverse engineering</a> που μπορείτε να χρησιμοποιήσετε αν ασχολείστε με το &#8220;σπόρ&#8221;.</p>
<h3>Servant Salamander</h3>
<p>Το <a href="http://www.altap.cz/salam_en/index.html">Servant Salamander</a> είναι ένα φανταστικό εργαλείο γενικά για development αλλα και για απλούς χρήστες. Το salamander είναι ένας file manager που θυμίζει λίγο το παλιό norton commander, ωστόσο παρέχει αρκετές ευκολίες για τους επαγγελματίες χρήστες του, όπως file compare, ενσωματομένο ftp και sftp client, κτλ. Αξιοσημείωτο οτι ακόμα και στην αντιγραφή αρχείων είναι πιό γρήγορος απο τα windows <img src='http://developstories.gr/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<h3>EmEditor</h3>
<p>O <a href="http://www.emeditor.com/">emEditor</a> είναι ένας απλός text editor ο οποίος παρέχει ένα βασικό code highlighting και &#8220;παίζει&#8221; με οποιοδήποτε encoding(και UTF8). Δέν παρέχει τις ευκολίες ενός επαγγελματικού IDE ωστόσο είναι πολύ καλό για την περίπτωση που θέλουμε να επεξεργαστούμε ένα αρχείο γρήγορα.</p>
<h3>Hex Editor</h3>
<p>Ένας hex editor είναι τουλάχιστον απαραίτητος για όποιον ασχολείται με reverse engineering. Προσωπικά χρησιμοποιώ τον <a href="http://www.x-ways.net/winhex/">WinHex</a> αλλά μπορείτε να δείτε και τον <a href="http://www.chmaas.handshake.de/delphi/freeware/xvi32/xvi32.htm">xvi32</a> που είναι freeware.</p>
<h3>IDA Pro Dissasembler &amp; Debugger</h3>
<p>Ο  <a href="http://www.hex-rays.com/idapro/">IDA Pro</a> είναι ένας πολύ δυνατός dissasembler. Το εργαλείο παρέχει και debugger ωστόσο για αυτή την χρήση καλύτερα προτιμίστε τον&#8230;</p>
<h3>OllyDbg Debugger</h3>
<p>Ο <a href="http://www.ollydbg.de/">OllyDbg</a> είναι ο πιό εύχρηστος debugger που έχω βρεί μεχρι στιγμής.</p>
<h3>RegMon</h3>
<p>Το <a href="http://technet.microsoft.com/en-us/sysinternals/bb896652.aspx">RegMon</a> είναι ένα utility που αγοράστηκε απο την Microsoft. Η δουλειά του είναι να σας δείχνει ποιές εφαρμογές κάνουν αλλαγές στο registry.</p>
<h3>FileMon</h3>
<p>Το <a href="http://technet.microsoft.com/en-us/sysinternals/bb896642.aspx">FileMon</a> που επίσης έχει εξαγοραστεί απο την Microsoft είναι ένα εργαλείο που παρακολουθεί τις αλλαγές στο filesystem σε real time.</p>
<h3>LordPE</h3>
<p>To <a href="http://www.woodmann.net/collaborative/tools/index.php/LordPE">LordPE</a>(<a href="http://www.woodmann.net/collaborative/tools/index.php/Image:Sc_LordPE_2008-2-4_2.43.png">screenshot</a>) είναι ένα freeware εργαλειάκι που διαχειρίζεται πολλά κομμάτια αρχείων PE (Portable Executable)</p>
<h3>Winspector</h3>
<p>Ο <a href="http://www.windows-spy.com/">Winspector</a> είναι ίσως το καλύτερο alternative για τον Spy++ που έρχεται με το Visual Studio.</p>
<h3>Resource Hacker</h3>
<p>Το τελευταίο προγραμματάκι στην λίστα μας, ο <a href="http://www.angusj.com/resourcehacker/">Resource Hacker</a>, βοηθάει στην διαχείριση resource files. Μπορείτε να το χρησιμοποιήσετε για να δείτε ή και να επεξεργαστείτε resource files και resources απο εκτελέσιμα αρχεία.</p>
<h3>Bonus εργαλείο</h3>
<p>Το 11ο εργαλείο που παρουσιάζουμε σήμερα, είναι μια δική μου, open source, προσθήκη για <a href="http://developstories.gr/cat/php/">php</a> developers. Ονομάζεται <a href="http://code.google.com/p/phphexed/">php hexed</a> και χρησιμοποιείται  σαν patch script engine και μπορεί να συνεργάζεται με τον Win32Dasm  και με τον OllyDbg. Αργότερα θα κάνω post κάποιο παράδειγμα, οπότε αν σας ενδιαφέρει <a href="http://feeds.feedburner.com/DevelopStories">μείνετε συντονισμένοι</a> <img src='http://developstories.gr/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://developstories.gr/php/10-must-%ce%b5%cf%81%ce%b3%ce%b1%ce%bb%ce%b5%ce%af%ce%b1-%ce%b3%ce%b9%ce%b1-reverse-engineering/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>FirePHP για την έκδοση 4 του PHP</title>
		<link>http://developstories.gr/php/firephp-%ce%b3%ce%b9%ce%b1-%cf%84%ce%b7%ce%bd-%ce%ad%ce%ba%ce%b4%ce%bf%cf%83%ce%b7-4-%cf%84%ce%bf%cf%85-php/</link>
		<comments>http://developstories.gr/php/firephp-%ce%b3%ce%b9%ce%b1-%cf%84%ce%b7%ce%bd-%ce%ad%ce%ba%ce%b4%ce%bf%cf%83%ce%b7-4-%cf%84%ce%bf%cf%85-php/#comments</comments>
		<pubDate>Sat, 06 Dec 2008 10:19:36 +0000</pubDate>
		<dc:creator>Kostas Theodorou</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[firePHP]]></category>

		<guid isPermaLink="false">http://developstories/?p=32</guid>
		<description><![CDATA[Είμαι σίγουρος ότι δεν υπάρχει web developer που να μην γνωρίζει το Firebug. Για όποιον δεν το γνωρίζει είναι ένα firefox extension που βοηθάει τον developer στην κατασκευή ενός site. Μπορείτε να επεξεργαστείτε και να κάνετε debug javascript, css και html πάνω στα πραγματικά δεδομένα και σε πραγματικό χρόνο. Βεβαία οι δυνατότητες του δεν έχουν [...]]]></description>
			<content:encoded><![CDATA[<p>Είμαι σίγουρος ότι δεν υπάρχει web developer που να μην γνωρίζει το <a href="http://getfirebug.com/index.html">Firebug</a>. Για όποιον δεν το γνωρίζει είναι ένα <a href="http://en.wikipedia.org/wiki/List_of_Firefox_extensions">firefox extension</a> που βοηθάει τον developer στην κατασκευή ενός site. Μπορείτε να επεξεργαστείτε και να κάνετε debug javascript, css και html πάνω στα πραγματικά δεδομένα και σε πραγματικό χρόνο. Βεβαία οι δυνατότητες του δεν έχουν όρια…, εγώ πχ. σαν <a href="http://en.wikipedia.org/wiki/Reverse_engineering">reverser</a> τον χρησιμοποιώ και διαφορετικά. Δεν θέλω να επεκταθώ παραπάνω για τον firebug γιατί δεν είναι και το θέμα του άρθρου. Όποιος όμως θέλει να μάθει περισσότερα μια αναζήτηση στο <a href="http://www.google.com/search?hl=en&amp;q=firebug">google</a> και θα βρει αξιόλογα πράγματα. Εγώ βρηκα σε ένα <a href="http://www.chatzimanolis.gr/post/11-Tips-ceb3ceb9ceb1-cf84cebf-Firebug.aspx">ελληνικό blog 11 tips</a>.</p>
<p>Ξεφύγαμε στο θέμα μας. <a href="http://www.firephp.org/">FirePHP</a> ένα πολύ δυνατό firefox extension που παράλληλα με το firebug μπορούμε να κατευθύνουμε τα php (error και debug) μηνύματα μας στην κονσόλα του firebug. Στο site του firephp μπορείτε να βρείτε μία php class που μπορείτε να την ενσωματώσετε στο project σας και να χρησιμοποιείτε την firebug console.</p>
<p>Τι γίνεται όμως αν χρησιμοποιείτε την έκδοση 4 του <a href="http://www.php.net/">php</a> ακόμα ? Δεν υπάρχει τίποτα και δεν πρόκειται να βγάλουν, διότι όσο έψαξα, όλοι λένε &#8220;php4 is dead&#8221;. Προσωπικά δεν νομίζω να ισχύει αυτό διότι υπάρχουν πολλά projects που τρέχουν σε php4 και δεν έχουν περάσει σε php5. Εμείς π.χ. στην <a href="http://www.netwerk.gr/">Netwerk</a> δεν έχουμε γυρίσει 100% σε php5 σε όλα μας τα project.</p>
<p>Έτσι σκέφτηκα να δημιουργήσω from scratch (πολύ το γουστάρω αυτό) μία function που να εμφανίζει της μεταβλητές που θέλω, σε πρώτη φάση, και στην συνέχεια να την ενσωματώσω στον <a href="http://www.php.net/set-error-handler">error handler</a> του php και στον mysql error handler ώστε να μου εμφανίζει τα php και mysql errors. Το ποιο ωραίο είναι ότι μπορείς να δεις και ένα dump από ένα mysql query με μορφή table καθώς και ένα πολύπλοκο array ή object, γιατί ανοίγει ένα παραθυράκι στη μέση της οθόνης με scroll.</p>
<p>Το καλό με τον firephp είναι ότι δεν σου χαλάει το site ένα error που θα εμφανιστεί ή ένα dump που θέλεις να κάνεις. Άντε πολύ ασχοληθήκαμε με την θεωρεία, πάμε σε λίγο ανάλυση και κώδικα.</p>
<p>Πως δουλεύει ο firephp; Πολύ έξυπνο χρησιμοποιεί δικούς του headers με μία πολύ έξυπνη δομή. Υπάρχει η προηγούμενη έκδοση <a href="http://www.firephp.org/Wiki/Reference/Protocol">X-FirePHP</a> (ασχολήθηκα λίγο και την παράτησα) και η τωρινή <a href="http://code.google.com/p/firephp/issues/detail?id=63">X-Wf</a> που είναι πολύ ποιο βελτιωμένη.</p>
<p>Έφτιαξα λοιπόν μια function την dev (την ονόμασα έτσι γιατί την είχα και παλιά, απλά τα τύπωνε στον browser), η οποία στην ουσία στέλνει τα κατάλληλα headers. Για json χρησιμοποείσα την php class <a href="http://mike.teczno.com/JSON/JSON.phps">Services_JSON</a>.</p>
<pre class="brush: php; title: ; notranslate">
function dev($a0) {
static $messageIndex=1;
if ($messageIndex==1) {
header('X-Wf-Protocol-1:http://meta.wildfirehq.org/'.'Protocol/JsonStream/0.2');
header('X-Wf-1-Plugin-1:http://meta.firephp.org/'.'Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.2.0');
header('X-Wf-1-Structure-1:http://meta.firephp.org/'.'Wildfire/Structure/FirePHP/FirebugConsole/0.1');
}
$type='INFO';
$args=func_get_args();
if (is_string($type)) {
$a0=strtoupper($a0);
if ($a0=='LOG' || $a0=='INFO' || $a0=='WARN' || $a0=='ERROR' || $a0=='TABLE') {
array_shift($args);
$type=$a0;
}
}

include_once('json.php');
$json = new Services_JSON();
$_ar=debug_backtrace();
if (strstr($_ar[0]['file'],'cmysql')) {
array_shift($_ar);
}
elseif (is_array($args[0]) &amp;amp;&amp;amp; $args[0][msg]) {
$_ar[0]=$args[0];
$args[0]=$args[0][msg];
}
foreach($args as $arg) {
if (is_resource($arg)) $arg=get_resource_type($arg);
$meta=array('Type'=&gt;$type,'File'=&gt;$_ar[0]['file'],
'Line'=&gt;$_ar[0]['line']);
$msg='['.$json-&gt;encode($meta).','.$json-&gt;encode($arg).']';
$parts=explode(&quot;\n&quot;,chunk_split($msg,5000,&quot;\n&quot;));
for($i=0; $i
$part = $parts[$i];
if ($part) {
if(count($parts)&gt;2) {
header('X-Wf-1-1-1-'.$messageIndex.':'.
(($i==0)?strlen($msg):'').'|'.
$part.'|'.(($i
}
else {
header('X-Wf-1-1-1-'.$messageIndex.':'.
strlen($part).'|'.$part.'|');
}
$messageIndex++;
}
}
}
}
</pre>
<p>Έπειτα χρησιμοποίησα την set_error_handler  και την σύνδεσα με την dev για να έχω και τα php error.</p>
<pre class="brush: php; title: ; notranslate">
function errorHandler($errno, $errmsg, $filename, $linenum, $vars) {
if(error_reporting()!=0) {
$errortype = array(
E_ERROR           =&gt; &quot;ERROR&quot;,
E_WARNING         =&gt; &quot;WARN&quot;,
E_PARSE           =&gt; &quot;ERROR&quot;,
E_USER_ERROR      =&gt; &quot;ERROR&quot;,
E_USER_WARNING    =&gt; &quot;WARN&quot;,
);
if ($errortype[$errno]) {
dev($errortype[$errno],array(&quot;msg&quot;=&gt;$errno.': '.
$errmsg,&quot;file&quot;=&gt;$filename,&quot;line&quot;=&gt;$linenum));
}
}
}
set_error_handler(&quot;errorHandler&quot;);
</pre>
<p>Σύνδεσα την κλάση που έχω για <a href="http://www.mysql.com/">mysql</a> query ώστε τα error να τα στέλνω στην dev. Τέλος μέσω της dev με τύπο table έδωσα τα αποτελέσματα των queries.</p>
<pre class="brush: php; title: ; notranslate">
function dump() {
$dbDump = new CMySql();
$dbDump-&gt;query($this-&gt;Query,-1);
$body=array();
$title = $this-&gt;Query.&quot; (rows: &quot;.$dbDump-&gt;num_rows().&quot;, fields: &quot;.($dbDump-&gt;num_fields()-1).&quot;)&quot;;
if ($dbDump-&gt;next()) {
$header = array();
foreach($dbDump-&gt;record() as $i=&gt;$v) $header[]=$i;
$body[] = $header;
do {
$row = array();
foreach($dbDump-&gt;record() as $v) $row[]=$v;
$body[] = $row;
}
while ($dbDump-&gt;next());
}
dev('table',array($title, $body));
}
</pre>
<p>Υπάρχουν και άλλοι τύποι στα headers που δεν ασχολήθηκα ακόμα. Trace, Dump και Groups, αλλά αυτά ας τα αφήσουμε στην php5, για να μην μας πουν ότι κάνουμε και προπαγάνδα κατά της ή ότι στηρίζουμε μόνο την php4. Απλά είναι κρίμα το firephp να είναι προνόμιο της php5, μόνο και μόνο επειδή το αποφάσισαν κάποιοι. Το μόνο configuration που χρειάζεται για να λειτουργήσουν τα παραπάνω, είναι να είναι ανοιχτό το <a href="http://www.webdigity.com/php-manual/ref.outcontrol.html#ini.output-buffering">output buffering</a> ή να χρησιμοποιήσετε την <a href="http://www.webdigity.com/php-manual/function.ob-start.html">ob_start()</a></p>
]]></content:encoded>
			<wfw:commentRss>http://developstories.gr/php/firephp-%ce%b3%ce%b9%ce%b1-%cf%84%ce%b7%ce%bd-%ce%ad%ce%ba%ce%b4%ce%bf%cf%83%ce%b7-4-%cf%84%ce%bf%cf%85-php/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Php mp3 id3 tag supports UTF-16</title>
		<link>http://developstories.gr/php/php-mp3-id3-tag-supports-utf-16/</link>
		<comments>http://developstories.gr/php/php-mp3-id3-tag-supports-utf-16/#comments</comments>
		<pubDate>Wed, 05 Nov 2008 10:15:05 +0000</pubDate>
		<dc:creator>Kostas Theodorou</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[id3]]></category>
		<category><![CDATA[mp3]]></category>

		<guid isPermaLink="false">http://developstories/?p=30</guid>
		<description><![CDATA[Βρήκα ένα php script για mp3 id3 tag, για να το χρησιμοποιήσω με μία ajax form, ώστε όταν επιλέγεις ένα αρχείο mp3 να σου εμφανίζει αυτόματα τα στοιχεία του τραγουδιού (όνομα, συγκρότημα κτλ). Όλα καλά ώσπου ανακάλυψα ότι μπορεί ένα αρχείο να έχει τα στοιχεία στο v2 του id3 σαν UTF-16. Αυτό το κατάλαβα όταν [...]]]></description>
			<content:encoded><![CDATA[<p>Βρήκα ένα <a href="http://en.wikipedia.org/wiki/PHP">php script</a> για <a href="http://rasher.dk/source/mp3/id3.php">mp3 id3 tag</a>, για να το χρησιμοποιήσω με μία <a href="http://en.wikipedia.org/wiki/AJAX">ajax</a> <a href="http://www.w3schools.com/TAGS/tag_form.asp">form</a>, ώστε όταν επιλέγεις ένα αρχείο <a href="http://en.wikipedia.org/wiki/MP3">mp3</a> να σου εμφανίζει αυτόματα τα στοιχεία του τραγουδιού (όνομα, συγκρότημα κτλ). Όλα καλά ώσπου ανακάλυψα ότι μπορεί ένα αρχείο να έχει τα στοιχεία στο v2 του <a href="http://en.wikipedia.org/wiki/ID3">id3</a> σαν UTF-16. Αυτό το κατάλαβα όταν στην φόρμα αντί να εμφανιστούν χαρακτήρες εμφάνιζε κουτάκια, ενώ με ένα <a href="http://en.wikipedia.org/wiki/MP3_player">mp3 player</a> εμφανιζόταν κανονικά. Τότε με ένα <a href="http://en.wikipedia.org/wiki/Hex_editor">hex editor</a> και συγκεκριμένα τον αγαπημένο μου <a href="http://www.x-ways.net/winhex/index-m.html">WinHex</a> ανακάλυψα ότι τα στοιχεία ήταν σε <a href="http://en.wikipedia.org/wiki/UTF-16">UTF-16</a>. Έτσι πείραξα λίγο το script, και τώρα υποστηρίζει και UTF-16.</p>
<p>Στην γραμμή 244 αντί για:<br />
<span style="color: #ff0000;"><code>$this-&gt;v2[$name] = substr($frame, 1);</code></span><br />
έβαλα αυτό:<br />
<span style="color: #3333ff;"><code>$this-&gt;v2[$name] = $encoding=="\01" ? iconv("UTF-16","UTF-8",substr($frame, 1)) : substr($frame, 1);</code></span></p>
]]></content:encoded>
			<wfw:commentRss>http://developstories.gr/php/php-mp3-id3-tag-supports-utf-16/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

