Draudzīgas saites būvēšana

16
Dec
2

Kā jau ierasts, runa ir par informācijas meklētājiem draudzīgām saitēm, izmantojot mod_rewrite moduli. Principā saites ģenerēšana vairumā gadījumu nav sarežģīts process, šī lieta tiek sarežģīta brīdī, kad izejot no vienas lapas, nepieciešams saražot lielu daudzumu citu saišu – visbiežāk meklēšana vai lapas karte.

Iepriekš savos rakstos esmu parādījis, kā nevajadzētu darīt, diemžēl, šoreiz tas izpaliks, jo rakstīšana ar savu jauno mini-datoru nebūt nav tik viegla. Biežāk izmantotais risinājums šai problēmai saistās ar pieprasījumu veidošanu uz datubāzi ciklā, patiesībā cikls ciklā – tiek atrasti vajadzīgie ieraksti datubāzē, ciklējot caur ierakstiem tiek izsaukta saites ģenerēšanas funkcija, kas arī satur ciklu.

Mans risinājums. Atkal pieņemam, ka strādājam ar klasisko koka struktūru.

+----+-----------+----------+----------+
| id | parent_id | name     | url      |
+----+-----------+----------+----------+
| 1  | 0         | Sākums   | home     |
+----+-----------+----------+----------+
| 2  | 0         | Kontakti | contacts |
+----+-----------+----------+----------+
| 3  | 1         | Raksti   | news     |
+----+-----------+----------+----------+
| 4  | 1         | Foto     | photo    |
+----+-----------+----------+----------+
| 5  | 2         | Karte    | map      |
+----+-----------+----------+----------+

Lai mums katru reizi nevajadzētu pieprasīt sadaļu sarakstu no jauna, saglabājam vajadzīgo masīvā, izejot no funkcijai padotās sadaļas id, izveidosim saiti.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?
  function url($id){
    global $urldata;
	if(!is_array($urldata)){
	  return false;
	}elseif(!array_key_exists($id,$urldata)){
	  return "";
	}
	$url=$urldata[$id][0];
	$url.=$urldata[$id][1];
	return $url;
  }
  $urldata=array();
  $sql="SELECT id, parent_id, url FROM `topics`";
  $res=mysql_query($sql);
  while($row=mysql_fetch_object($res)){
    $urldata[$row->id]=array($row->parent_id,$row->url);
  }
?>

Pēc tam jau viss notiek vienkārši :)

Terminator Salvation

11
Dec
4

Terminator SalvationNezinu kā Jums, bet man, jaunās Terminatora filmas iznākšana, bija pārsteigums.

Filma uz ektrāniem būs redzama no 2009. gada 22. maija. Galveno lomu vairs neatveidos visu iepriekšējo filmu varonis Arnolds (bez komentāriem), bet gan Christian Bale.

Noskatijos treileri un pār mani apgaismība tā arī nenāca, sižets – wtf? Man pat radās aizdomas, ka šī filma varētu būt neatkarīga – nesaistīta ar iepriekšējām, bet nu tas ir tikai mans priekšstats, iespējams, tajā ir vainīga šī darba diena.

Filed under: Filmas

Skaties.

9
Dec
0

Kamēr visi priecājas par Slaktera kunga nedienām, es uzgāju kādu video klipu un kaut kas man lika to noskatīties vēl pāris reizes. Skatieties arī Jūs.

Filed under: Mūzika

Vizitkarte – vertikāli, horizontāli centrēta lapa

8
Dec
2

Viens no šī laika “grūtākajiem” layout’iem – vertikāli un horizontāli centrēta lapa, visbiežāk vizitkartes tipa mājaslapa. Šīs problēmas risinājumi arī ir redzēti daudz un dažādi, liekākā daļa, diezgan, līki. Visvieglāk būtu izveidot 100%x100% tabulu ar atribūtiem align=”center” un valign=”middle”, bet priekškam lietot tabulu tur, kur tas nav vajadzīgs? Otrs biežāk pielietotais variants ir tabulas atdarināšana ar elementiem, proti, style=”display: table;” utt. Turklāt šādiem risinājumiem ir problēmas ar XHTML 1.0 Strict un pārlūku savietojamībām.

Parādīšu, kā to daru es, zinot centrējamā elementa augstumu.

CSS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
* {
  margin: 0;
  padding: 0;
}
 
html, body {
  height: 100%;
}
 
body {
  background-color: #fff;
  font-family: Arial;
  font-size: 12px;
  color: #000;
  text-align: justify;
}
 
#top {
  width: 100%;
  height: 50%;
  /* šis elements nebrauks virsū wrapper'im */
  position: relative;
  z-index: -1;
}
 
#wrapper {
  margin: -150px auto 0 auto; /* puse no elementa augstuma */
  padding: 30px;
  width: 440px;
  height: 240px;
  background-color: #eee;
}

HTML

1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
 <head>
  <title>Mana lapa</title>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <link rel="stylesheet" href="/css/layout.css" type="text/css" media="screen" />
 </head>
<body>
 <div id="top">&nbsp;</div>
 <div id="wrapper">Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. </div>
</body>
</html>

Dabā to varam redzēt šeit.
Testēts uz Microsoft Internet Explorer 6, Microsoft Internet Explorer 7, Mozilla Firefix 3, Netscape Navigator 9, Apple Safari 3, Google Chrome, Opera 9.

draugiem.lv API PHP wrapper

7
Dec
6

Jau pāris dienas atpakaļ rakstiju par draugiem.lv jaunajām iespējām un vēlmi apskatīt tās tuvāk. Domāts, darīts.

Pieprasījumu veikšana uz draugiem.lv API ir ļoti vienkārša – HTTP GET vai POST. Ja pieprasījums noritējis veiksmīgi, tad atpakaļ tiek saņemti dati xml formātā. Ar to nekādām problēmām nevajadzētu būt.

Sistēma ir sekojoša, lai mēs nevarētu kaut kā manipulēt ar cilvēku datiem, katram lietotājam ir jādod piekrišana, ārējai aplikācijai, lai tā varētu iegūt datus par konkrēto lietotāju, kas ir loģisks solis. Pats apstiprināšanas process gan ir samudrīts līdz pēdējam. Nav man jēgas to stāstīt, jo tas tāpat ir labi izlasāms oficiālajā dokumentācijā.

Principā, vienīgais, ko es ieguvu izveidojot savu wrapperi ir ērta pieprasījumu veikšana un saņemto datu automātiska apstrāde. Apskatīsim, kā tad notiek šīs klases lietošana praksē.

1
2
3
4
5
6
7
8
9
10
11
12
13
<?
  include("class_draugiem_inc.php"); // pats par sevi skaidrs
  $dr=new draugiem; // tāpat
  $dr->app='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'; // aplikācijas identifikators (obligāts)
  $dr->apikey='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'; // lietotāja identifikators (nav obligāts)
  $action=""; // komanda (obligāts)
  $params=array(); // citi parametri (nav obligāts)
  if($response=$dr->execute($action,$params)){
    print_r($response);
  }else{
    die("Kaut kas aizgājis pa kāju!");
  }
?>

Lejuplādējam šeit.

draugiem.lv un Google Reader jaunumi

5
Dec
0

Vakar bija jaunumu un arī darba pilna diena, tapēc pastāstīt par lielo portālu jaunumiem centīšos šodien.

Sāksim ar draugiem.lv, kuru solijums par API izveidi beidzot ir piepildijies. Kā viņi paši saka, tad šī ir beta versija un iespējas esot visai ierobežotas, bet ar laiku tas viss mainīsies.
Nezinu kāds varētu mans vai tavs lielais ieguvums no šīs iespējas, bet nu pricipa pēc, domāju, ka pa brīvdienām uztaisīšu kādu PHP draugiem.lv API klasi, tad arī padalīšos iespaidos, par tā lietošanas ērtumu.

Otrais lielais notikums ir Google Reader jaunais izskats, pieļauju, ka arī dzinējs. Parcik lietoju šo pakalpojumu ikdienā, tad vakar vakarā, pārnācis pēc garas darba dienas mājās, kārtējo reizi nolēmu apskatīt kas jauns pasaulē un man par pārsteigumu Google’s lasītājs strādāja neierasti lēni. Kad tas beidzot atvērās bija skaidrs, kāpēc man nācās tik ilgi gaidīt – ir uzstādīta jauna versija un, acīmredzot, kautkas strādāja nepareizi. Šodien viss ir kārtībā. Lai arī izskata ziņā nekas nopietni nav mainijies, jaunā versija man patīk labāk, arī ātrums šobrīd ir labāks, nekā tas bija vecajai versijai.

Lasam urli.

3
Dec
0

Nu jau kāds laiks pagājis, kopš parādijies tāds brīnums kā mod_rewrite priekš Apache. Tas padara mūsu mājaslapas draudzīgākas gūglei un cilvēkiem. Kāpēc? Jo jau saitē mēs redzam ar ko saistīta konkrētā sadaļa vai raksts. Pats personīgī, šķiet, bez šī rīka vairs īsti nemāku strādāt.

Sāksim ar rewrite nosacījumu uzstādīšanu. Iespējas ir dažādas un atkarīgas no vajadzībām, piemēram, mēs varam, caur slešiem atdalītus vārdus, padot kā $_GET mainīgos vai ļaut rakstīt jebko un padoto saiti apstrādāt ar server-side skriptiem. Esmu piekopis otro metodi un lai labāk saprastu, parādīšu savu RewriteRule.

<VirtualHost *>
    DocumentRoot /home/www/domens
    ServerName domens.lv
    ServerAlias www.domens.lv

    RewriteEngine On
    AcceptPathInfo On
    RewriteRule ^/lv/(.*) /lv.php/$1
    RewriteRule ^/ru/(.*) /ru.php/$1
    RewriteRule ^/en/(.*) /en.php/$1
</VirtualHost>

Jā, rewrite nosacījumus rakstu Apache konfigurācijas failā, nevis .htaccess failā. Lūk, manā gadījumā, viss, kas sekos aiz domens.lv/lv/, tiks pārrakstīts.

Iekš lv.php, ru.php, en.php tiek definēti izvēlētās valodas apzīmējoši mainīgiem un inklūdots fails, kas inklūdo pārējos failus, taisa konekcijas ar datubāzi un, protams, apstrādā padoto saiti.

Apskatīsim mūsu mājaslapas sadaļu tabulu, kas dzīvo MySQLā. Manā gadījumā tā izskatās līdzīga šai:

+----+-----------+----------+----------+----------+----------+----------+
| id | parent_id | position | url      | name_lv  | name_ru  | name_en  |
+----+-----------+----------+----------+----------+----------+----------+
| 1  | 0         | 1        | main     | Sākums   | Начало   | Home     |
+----+-----------+----------+----------+----------+----------+----------+
| 2  | 0         | 2        | contacts | Kontakti | Контакты | Contacts |
+----+-----------+----------+----------+----------+----------+----------+
| 3  | 1         | 2        | news     | Jaunumi  | Новости  | News     |
+----+-----------+----------+----------+----------+----------+----------+
| 4  | 1         | 1        | photo    | Foto     | Фото     | Photo    |
+----+-----------+----------+----------+----------+----------+----------+
| 5  | 2         | 1        | map      | Karte    | Карта    | Map      |
+----+-----------+----------+----------+----------+----------+----------+

Tagad Iedomāsimies, ka cilvēks ir ieradies lapā, ar adresi domens.lv/lv/contacts/map. Atvērtās sadaļas ID ir 5. Kā mēs to noskaidrosim ar PHP? Sākumā apstrādāsim saņemto saiti:

1
2
3
4
5
6
7
<?
  $xpieces=explode("/",$_SERVER['PATH_INFO']);
  $cnt=count($xpieces);
  if(empty($xpieces[--$cnt])){
    unset($xpieces[$cnt]);
  }
?>

Kā redzams, izmantoju $_SERVER['PATH_INFO'] mainīgo (to ir iespējams ieslēgt tikai Apaches konfigurācija un noklusējuma uzstādījumos šis mainīgais neparādās), šis mainīgais man atgriež “lv/contacts/map”.

Tiksim pie atvērtās sadaļas ID! Atkal jāsaka, ka esmu redzējis dažādus variantus – tādus, kas skatās tikai pēc pēdējās sadaļas un tādus, kas uz katru direktoriju taisa jaunu pieprasījumu uz datubāzi.
Pirmais variants būs pietiekami ātrs, bet ceļš netiks ņemts vērā, kā arī kolonai “url”, datubāzē, jābūt unikālai vērtībai.
Otrs variants jau būs labāks, katras sadaļas saitei (”url” kolona datubāzē) jābūt unikālai pie katra “parent_id”. Turklāt, meklējot atvērtās sadaļas id, ir iespējams savākt datus par iepriekšējām sadaļām, ja nu kādam tas ir vajadzīgs. Rādīšu kolēģa rakstītu piemēru:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?
  function get_lastid($pid,$i=1){
    global $xpieces;
    $sql="SELECT id FROM `topics` WHERE parent_id=".intval($pid)." AND url='".mysql_real_escape_string($xpieces[$i])."' LIMIT 1";
    $res=mysql_query($sql);
    if(mysql_num_rows($res)<1){
      return $pid;
    }
    $row=mysql_fetch_object($res);
    return get_lastid($row->id,++$i);
  }
  $lastid = get_lastid(0);
?>

Šī funkcija veiks pārāk daudz lieku pieprasījumu uz datubāzi, turklāt, ja kāda sadaļa, datubāzē, būs ar tukšu “url” lauku un parent_id būs vienāds ar atvērtās sadaļas ID, tad funkcija mainīgajam $lastid piešķirs šīs sadaļas ID. Tādēļ ķersimies klāt vienam selektam un masīviem.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?
  function get_lastid($arr,$pid=0,$i=1){
    global $xpieces;
    if(!is_array($arr[$pid])){
      return $pid;
    }
    $n=array_search($xpieces[$i],$arr[$pid]);
    if(!$n){
      return $pid;
    }
    return get_lastid($arr,$n,++$i);
  }
 
  $all=array();
  $allsql="SELECT id, parent_id, url FROM `topics` ORDER BY position ASC";
  $allres=mysql_query($allsql);
  while($allrow=mysql_fetch_object($allres)){
    $all[$allrow->parent_id][$allrow->id]=$allrow->url;
  }
  $lastid=get_lastid($all);
?>

Rekursīva lapas karte

1
Dec
2

Tā nu ir sanācis, ka esmu mājaslapu izstrādātājs un šoreiz gribu padalīties ar kādu jauku algoritmu – lapas karte.

Sākumā apstāstīšu, ar ko esmu saskāries vairumā gadījumu. Liela daļa mājaslapu ir būvētas klasiskajā koka algoritmā, ko es atbalstu – id, parent_id. Šajā gadījumā tabula izskatīsies, aptuveni, šādi:

+----+-----------+----------+----------+
| id | parent_id | name     | position |
+----+-----------+----------+----------+
| 1  | 0         | Sākums   | 1        |
+----+-----------+----------+----------+
| 2  | 0         | Kontakti | 2        |
+----+-----------+----------+----------+
| 3  | 1         | Raksti   | 2        |
+----+-----------+----------+----------+
| 4  | 1         | Foto     | 1        |
+----+-----------+----------+----------+
| 5  | 2         | Karte    | 1        |
+----+-----------+----------+----------+

Funkcija, kuru izmanto veidojot rekursīvu lapas karti, uz šāda tipa datubāzes struktūras, visbiežāk izskatās šādi:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?  
  function sitemap($pid){
    $sql="SELECT id, name FROM `topics` WHERE parent_id=".intval($pid)." ORDER BY position ASC";
    $res=mysql_query($sql);
    if(mysql_num_rows($res)<1){
      return "";
    }
    $s='<ul>';
    while($row=mysql_fetch_object($res)){
      $s.='<li>';
      $s.=$row->name;
      $s.=sitemap($row->id);
      $s.='</li>';
    }
    $s.='</ul>';
    return $s;  	
  }       
  echo sitemap(0);
?>

Iedomājamies, ka ir tāda nopietnāka lapa, piemēram, ar 10 pirmā līmeņa sadaļām un katrai pirmā līmeņa sadaļai ir 5 apkšsadaļas. Cik pieprasījumi tiks sūtīti uz datubāzi?  1+10*5=26
Kapēc veidot 26 pieprasījumus, ja var iztikt ar vienu? Izmantosim sarežģītāku, taču ātrāku, algoritmu.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?
  function sitemap($pid,$arr){
    if(!is_array($arr[$pid])){
      return "";
    }
    $s='<ul>';
    foreach($arr[$pid] as $key=>$value){
      $s.='<li>';
      $s.=$value;
      $s.=sitemap($key,$arr);
      $s.='</li>';
    }
    $s.='</ul>';
    return $s;
  }
 
  $topics=array();
  $sql="SELECT id, parent_id, name FROM `topics` ORDER BY position ASC";
  $res=mysql_query($sql);
  while($row=mysql_fetch_object($res)){
    $topics[$row->parent_id][$row->id]=$row->name;
  }
  echo sitemap(0,$topics); 
?>

Testējot koda izpildes laiku (uz lēnas kastes, lai atšķirību vieglāk pamanīt), pirmā algoritma izpildes laiks bija ~ 0.77 sekundes, bet otrā ~ 0.015 sekundes. Atšķirība ir diezgan paliela, ņemot vērā, ka lapai, uz kuras tika veikts tests, nebija diezko daudz sadaļu.