יום ראשון, 18 בדצמבר 2011

המרות של סוגי קבצים

ImageMagick
convert

יום חמישי, 27 באוקטובר 2011

Linux Run Level and Services Deamon config

נושא ה - services וה - deamons ב - linux תמיד היה נושא קצת מסובך אבל חשוב.
אילו שרותים עולים כאשר מערכת ההפעלה עולה, מה תפקידם, מתי הם מתחילים וכיצד ניתן לנהל אותם.

הדברים מוסברים בצורה פשוטה כאן:
http://en.wikipedia.org/wiki/Runlevel
http://www.ubuntu-unleashed.com/2007/09/i-personally-like-gui-tools-but-i-also.html

אבל שתי תוכנות חמודות חדשות שמצאתי עוזרות לנהל את ספריית ה- rc בצורה נוחה:
rcconfig
ו - sysv-rc-conf
שתי התוכנות עם ממשק TUI שאני כל כך אוהב. (TUI - Text User Interface)
בניגוד ל - command line שדורשות פקודות בשורת הפקודה ובניגוד ל - GUI שמחייב הרצה של ממשק גרפי מלא (XServer) תוכנות TUI מאפשרות עבודה נוחה ב - text.

התוכנות מאפשרות ניהול והחלטה אילו deamons (שרותים) יופעלו באיזה runlevel.




יום שני, 19 בספטמבר 2011

UTF8 ובסיסי נתונים MySQL Database

זה כבר כמה זמן אני מעוניין לכתוב על ניהול נכון של Encoding בבניית אתרי אינטרנט. אנשים נוטים לבצע טעויות רבות ולא מבינים את המשמעות שבין UTF-8 לבין תקני ISO ותקנים של Windows כגון Windows-1255. הבעיות מופיעות בבחירה לא נכונה של Charset הן בבניית העמוד והן בשמירה ב - Database.

לצערי אין לי את הזמן כרגע, אבל אני בוודאי שעוד אחזור לכך ואסביר את כל שלבי ה - Encoding מה - Datbase דרך ה - Webserver וכלה בדף ה- HTML והתצוגה בדפדפן.

כרגע אני משתף קוד קצר ל - mysql שימיר לנו שדות טקסט ששמרנו בהם עברית ב - Charset latin1 ל - UTF8.


ALTER TABLE files ADD COLUMN temp TEXT CHARACTER SET utf8 COLLATE utf8_general_ci AFTER text; -- add the temp column

UPDATE files SET temp=CONVERT(CONVERT(text USING binary) USING utf8); -- convert the data to the new column


ALTER TABLE files DROP COLUMN text; -- drop original column


ALTER TABLE files CHANGE temp text TEXT CHARACTER SET utf8 COLLATE utf8_general_ci; -- rename temp column


Change hebrew / or other charset inside MySQL to UTF-8.


יום ראשון, 10 ביולי 2011

PHP וחילוץ נתונים מתוך HTML

במקרים רבים (ואנשים רבים שואלים אותי) אנחנו צריכים לחלץ נתונים מאתרי אינטרנט ודפי HTML.
מהי הדרך הטובה ביותר לעשות זאת? ומהי הדרך הנוחה ביותר לעשות זאת?

כמובן שאם האתר מספק לנו נתונים באמצעות XML או באופן מדוייק יותר RSS הפתרון הוא קל יחסית, ושימוש ביכולות המובנות של PHP לניתוח XML/RSS באות לעזרתנו. לדוגמא, simple_xml_loadfile.

אך מה קורה אם אין אפשרות לגשת לאתר לקבלת מידע בפורמטים מקובלים כמו XML/RSS או JSON, ואנו נאלצים לפרסס (Parsing)\ לנתח את הדף בעצמנו?

לכך מצאתי כמה פתרונות נחמדים:
הראשון, הפשוט יותרת שימוש בפונקציה אשר מחלצת נתונים המופיעים בין שתי מחרוזות (strings).
השני המתוחכם יותרת והנוח יותר הוא שימוש בספריית php המיצרת לנו DOM בתוך ה - PHP ומאפשרת לבצע שאילתות DOM וכן Selectors מתוך קוד ה - php על דף ה - HTML אותו אנו מנסים לפענח.



לפתרון הראשון:
// $text - is the full text we are searching on
// $from - is the opening text we start taking data from
// $to - is array of optional ending text we will fetch text until
// text_between('this is a full text', 'is', array('text')) - will return: ' is a full '
function text_between($text, $from, array $to)
{
$start = strpos($text, $from);
if($start === false)
return null;

$end = array();
for($i = 0; isset($to[$i]); ++$i)
{
$e = strpos($text, $to[$i], $start + strlen($from));
if($e !== false)
$end[] = $e;
}

$end = min($end);
return substr($text, $start + strlen($from), $end - $start - strlen($from));
}



הפתרון השני, שימוש בספרייה חיצונית הנקראת PHP Html DOM Parser
אשר מאפשר לבצע שאילתות DOM ישירות מתוך קוד ה - PHP גם באמצעות CSS Selectors כאילו אנחנו עובדים מתוך JavaScript או כל XML אחר.



// Create DOM from URL or file
$html = file_get_html('http://www.google.com/');

// Find all images
foreach($html->find('img') as $element)
echo $element->src . '';

// Find all links
foreach($html->find('a') as $element)
echo $element->href . '';




יום חמישי, 2 ביוני 2011

הפיכת XML ל - JSON

דינוזאורים עדיין עובדים על XML בכל מיני מקומות לצערי. זה נכון XML נותן הרבה יותר יכולות ש - JSON לא, אבל עדיין, JSON זה פשוט כיף.

לעיתים אנחנו נתקלים בצורך להמיר XML ל - JSON מתוך JavaScript, כמו לדוגמא בשימוש בתוך Firefox Extension או קריאות Ajax ו - XSS Cross Sites ּScripting.

ישנן הרבה ספריות ברשת להמרת XML ל - JSON רק חלקן ב - JavaScript ורובן לא עובדות.
מצאתי אחת שכן עובדת:
http://michael.hinnerup.net/blog/wp-content/uploads/2008/01/JsonXml.js
http://michael.hinnerup.net/blog/2008/01/26/converting-json-to-xml-and-xml-to-json/



/*
The below work is licensed under Creative Commons GNU LGPL License.

Original work:

License: http://creativecommons.org/licenses/LGPL/2.1/
Author: Stefan Goessner/2006
Web: http://goessner.net/

Modifications made:

Version: 0.9-p5
Description: Restructured code, JSLint validated (no strict whitespaces),
added handling of empty arrays, empty strings, and int/floats values.
Author: Michael Schøler/2008-01-29
Web: http://michael.hinnerup.net/blog/2008/01/26/converting-json-to-xml-and-xml-to-json/
*/

/*global alert */
var xmlJsonClass = {
// Param "xml": Element or document DOM node.
// Param "tab": Tab or indent string for pretty output formatting omit or use empty string "" to supress.
// Returns: JSON string
xml2json: function(xml, tab) {
if (xml.nodeType === 9) {
// document node
xml = xml.documentElement;
}
var nws = this.removeWhite(xml);
var obj = this.toObj(nws);
var json = this.toJson(obj, xml.nodeName, "\t");
return "{\n" + tab + (tab ? json.replace(/\t/g, tab) : json.replace(/\t|\n/g, "")) + "\n}";
},

// Param "o": JavaScript object
// Param "tab": tab or indent string for pretty output formatting omit or use empty string "" to supress.
// Returns: XML string
json2xml: function(o, tab) {
var toXml = function(v, name, ind) {
var xml = "";
var i, n;
if (v instanceof Array) {
if (v.length === 0) {
xml += ind + "<"+name+">__EMPTY_ARRAY_\n";
}
else {
for (i = 0, n = v.length; i < n; i += 1) {
var sXml = ind + toXml(v[i], name, ind+"\t") + "\n";
xml += sXml;
}
}
}
else if (typeof(v) === "object") {
var hasChild = false;
xml += ind + "<" + name;
var m;
for (m in v) if (v.hasOwnProperty(m)) {
if (m.charAt(0) === "@") {
xml += " " + m.substr(1) + "=\"" + v[m].toString() + "\"";
}
else {
hasChild = true;
}
}
xml += hasChild ? ">" : "/>";
if (hasChild) {
for (m in v) if (v.hasOwnProperty(m)) {
if (m === "#text") {
xml += v[m];
}
else if (m === "#cdata") {
xml += "";
}
else if (m.charAt(0) !== "@") {
xml += toXml(v[m], m, ind+"\t");
}
}
xml += (xml.charAt(xml.length - 1) === "\n" ? ind : "") + "";
}
}
else {
if (v.toString() === "\"\"" || v.toString().length === 0) {
xml += ind + "<" + name + ">__EMPTY_STRING_";
}
else {
xml += ind + "<" + name + ">" + v.toString() + "";
}
}
return xml;
};
var xml = "";
var m;
for (m in o) if (o.hasOwnProperty(m)) {
xml += toXml(o[m], m, "");
}
return tab ? xml.replace(/\t/g, tab) : xml.replace(/\t|\n/g, "");
},

// Internal methods
toObj: function(xml) {
var o = {};
if (xml.nodeType === 1) {
// element node ..
if (xml.attributes.length) {
// element with attributes ..
var i;
for (i = 0; i < xml.attributes.length; i += 1) {
o["@" + xml.attributes[i].nodeName] = (xml.attributes[i].nodeValue || "").toString();
}
}
if (xml.firstChild) {
// element has child nodes ..
var textChild = 0, cdataChild = 0, hasElementChild = false;
var n;
for (n = xml.firstChild; n; n = n.nextSibling) {
if (n.nodeType === 1) {
hasElementChild = true;
}
else if (n.nodeType === 3 && n.nodeValue.match(/[^ \f\n\r\t\v]/)) {
// non-whitespace text
textChild += 1;
}
else if (n.nodeType === 4) {
// cdata section node
cdataChild += 1;
}
}
if (hasElementChild) {
if (textChild < 2 && cdataChild < 2) {
// structured element with evtl. a single text or/and cdata node ..
this.removeWhite(xml);
for (n = xml.firstChild; n; n = n.nextSibling) {
if (n.nodeType === 3) {
// text node
o["#text"] = this.escape(n.nodeValue);
}
else if (n.nodeType === 4) {
// cdata node
o["#cdata"] = this.escape(n.nodeValue);
}
else if (o[n.nodeName]) {
// multiple occurence of element ..
if (o[n.nodeName] instanceof Array) {
o[n.nodeName][o[n.nodeName].length] = this.toObj(n);
}
else {
o[n.nodeName] = [o[n.nodeName], this.toObj(n)];
}
}
else {
// first occurence of element ..
o[n.nodeName] = this.toObj(n);
}
}
}
else {
// mixed content
if (!xml.attributes.length) {
o = this.escape(this.innerXml(xml));
}
else {
o["#text"] = this.escape(this.innerXml(xml));
}
}
}
else if (textChild) {
// pure text
if (!xml.attributes.length) {
o = this.escape(this.innerXml(xml));
if (o === "__EMPTY_ARRAY_") {
o = "[]";
} else if (o === "__EMPTY_STRING_") {
o = "";
}
}
else {
o["#text"] = this.escape(this.innerXml(xml));
}
}
else if (cdataChild) {
// cdata
if (cdataChild > 1) {
o = this.escape(this.innerXml(xml));
}
else {
for (n = xml.firstChild; n; n = n.nextSibling) {
o["#cdata"] = this.escape(n.nodeValue);
}
}
}
}
if (!xml.attributes.length && !xml.firstChild) {
o = null;
}
}
else if (xml.nodeType === 9) {
// document.node
o = this.toObj(xml.documentElement);
}
else {
alert("unhandled node type: " + xml.nodeType);
}
return o;
},
toJson: function(o, name, ind) {
var json = name ? ("\"" + name + "\"") : "";
if (o === "[]") {
json += (name ? ":[]" : "[]");
}
else if (o instanceof Array) {
var n, i;
for (i = 0, n = o.length; i < n; i += 1) {
o[i] = this.toJson(o[i], "", ind + "\t");
}
json += (name ? ":[" : "[") + (o.length > 1 ? ("\n" + ind + "\t" + o.join(",\n" + ind + "\t") + "\n" + ind) : o.join("")) + "]";
}
else if (o === null) {
json += (name && ":") + "null";
}
else if (typeof(o) === "object") {
var arr = [];
var m;
for (m in o) if (o.hasOwnProperty(m)) {
arr[arr.length] = this.toJson(o[m], m, ind + "\t");
}
json += (name ? ":{" : "{") + (arr.length > 1 ? ("\n" + ind + "\t" + arr.join(",\n" + ind + "\t") + "\n" + ind) : arr.join("")) + "}";
}
else if (typeof(o) === "string") {
o = o.toString();
var objRegExp = /(^-?\d+\.?\d*$)/;
if (objRegExp.test(o)) {
// int or float
json += (name && ":") + o;
}
else {
json += (name && ":") + "\"" + o + "\"";
}
}
else {
json += (name && ":") + o.toString();
}
return json;
},
innerXml: function(node) {
var s = "";
if ("innerHTML" in node) {
s = node.innerHTML;
}
else {
var asXml = function(n) {
var s = "", i;
if (n.nodeType === 1) {
s += "<" + n.nodeName;
for (i = 0; i < n.attributes.length; i += 1) {
s += " " + n.attributes[i].nodeName + "=\"" + (n.attributes[i].nodeValue || "").toString() + "\"";
}
if (n.firstChild) {
s += ">";
for (var c = n.firstChild; c; c = c.nextSibling) {
s += asXml(c);
}
s += "";
}
else {
s += "/>";
}
}
else if (n.nodeType === 3) {
s += n.nodeValue;
}
else if (n.nodeType === 4) {
s += "";
}
return s;
};
for (var c = node.firstChild; c; c = c.nextSibling) {
s += asXml(c);
}
}
return s;
},
escape: function(txt) {
return txt.replace(/[\\]/g, "\\\\").replace(/[\"]/g, '\\"').replace(/[\n]/g, '\\n').replace(/[\r]/g, '\\r');
},
removeWhite: function(e) {
e.normalize();
var n;
for (n = e.firstChild; n; ) {
if (n.nodeType === 3) {
// text node
if (!n.nodeValue.match(/[^ \f\n\r\t\v]/)) {
// pure whitespace text node
var nxt = n.nextSibling;
e.removeChild(n);
n = nxt;
}
else {
n = n.nextSibling;
}
}
else if (n.nodeType === 1) {
// element node
this.removeWhite(n);
n = n.nextSibling;
}
else {
// any other node
n = n.nextSibling;
}
}
return e;
}
};


יום חמישי, 26 במאי 2011

jlinq הכיף שב - JavaScript

ספריית JavaScript חמודה שנתקלתי בה הינה ספריית jlinq.

jlinq היא ספריית JavaScript לביצוע שאילתות וחיתוכים על אובייקטי JSON מתוך JavaScript. משהו כמו לבצע שאילתות SQL על אובייקטים בזכרון במהלך הריצה של קוד JavaScript.

נניח ויש לנו אובייקט כזה:
data.users = [{id:1,name:'x', last:'y',age:32},
{id:2,name:'john', last:'do',age:10},
{id:3,name:'zoe', last:'brown',age:45},
{id:4,name:'jz', last:'kin',age:56}];

ננח שנרצה את כל המשתמשים שהשם שלהם מתחיל ב - j:
jlinq.from(data.users)
.starts('first', 'j').select()

ונניח שנרצה את כל אלו שהשם שלהם מתחיל ב - j והם מעל גיל 20 מסודרים לפי גיל:

jlinq.from(data.users)
.starts('first', 'j').greater('age',20).order('age').select()

הכוח של הספרייה הזו מאוד חזק. ומאפשרת המון שאילתות מאוד מתוחכמות שחוסכות לנו את כל לולאות ה - for שהיינו צריכים לכתוב.
הספרייה איננה דורשת jQuery ואפשר להשתמש בה בכל מקום ותואמת את כל הדפדפנים המתקדמים.

לאתר jLine