plain2click()

26
Nov
1

Nav ko te gari rakstīt. Nereti lietotāja ievadītajā tekstā nākas meklēt URL saites un pārtaisīt tās klikšķināmas. Lūk, strādājošs risinājums. Funkcija (otra tikai palīdz pirmajai :) ), kas tekstā sameklēs linkus un attiecīgi tos pārveidos par klikojamām saitēm vai e-pasta saitēm. Ja klikojamā saite būs links uz Youtube video, tad tā saite tiks pārvērsta par embed’u.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function plain2click($str){
	$str = preg_replace_callback("/(http(s)?\:\/\/|www\.)[a-z0-9\-\.]+\.[a-z]{2,4}(\/[a-z0-9\-\?=_&\+%#@\.\/]*)?/i", 'plain2clickCallback', $str);
	$str = preg_replace("/[a-z0-9\-\._]+@[a-z0-9\-\.]+\.[a-z]{2,4}/i", '<a href="mailto:$0">$0</a>', $str);
	return $str;
}
 
function plain2clickCallback($matches){
	$ymatches = array();
	if(preg_match("/http\:\/\/www\.youtube\.com\/watch\?v=([a-z0-9\-_]+)(&feature=[a-z]+)?/i", $matches[0], $ymatches)){
		return '<object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/'.$ymatches[1].'&hl=en_US&fs=1&"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/'.$ymatches[1].'&hl=en_US&fs=1&" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"></embed></object>';
	}
	$url = str_replace(array('http://', 'https://'), '', $matches[0]);
	return '<a rel="nofollow" href="http'.$matches[2].'://'.$url.'" onclick="window.open(this.href); return false;">'.$matches[0].'</a>';
}

Ja kaut kas nestrādā vai strādā nepareizi, tad padod ziņu komentāros, man gan līdz šim viss bijis ok.

Vēlreiz par lappusēm…

12
Jun
5

Nereti gadās situācijas, kad, piemēram, kaut kādu datu sarakstu jāsadala pa lappusēm. Vienreiz jau rakstīju, kāds, manuprāt, ir labākais risinājums lappušu skaita iegūšanai, šeit būs tāds kā turpinājums…

Ko darīt, ja lappušu skaits pārāk liels un visu lappušu linkus nav iespējams izvadīt? Protams, jāizvada tikai daļa no tām (arī pie tā raksta kāds jautāja par šādu algoritmu).

Nekā sarežģīta jau tur nav, bet vienmēr esmu rakstījis kaut kādu garu funkciju, kas rēķina sākuma ciparu un beigu ciparu, izejot no atvērtās lappuses. Pirms pāris nedēļām strādāju pie kāda foruma, kur radās šī pati problēma, taču šoreiz, dzerot aliņu, tika izdomāts algoritms, kurš aizņem, nevis 20, bet 2 rindiņas.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?
function draw_pages($count, $perpage, $offset = 5){
	$pages = ceil($count/$perpage);
	if($pages<2){
		return '';
	}
	$r = '<ul class="pages">';
	$page = (empty($_GET['p']) || $_GET['p']<2) ? 1 : $_GET['p'];
	$first = $page >= $offset+1 ? $page-$offset : 1;
	$last = $page <= $pages-$offset ? $page+$offset : $pages;
	if($page>1){
		$r.= sprintf('<li><a href="?p=1">«</a></li><li><a href="?p=%d">&lt;</a></li>', $page-1);
	}
	for($i=$first;$i<=$last;$i++){
		$r.= sprintf('<li%s><a href="?p=%d">%d</a></li>', $page==$i ? ' class="active"' : '', $i, $i);
	}
	if($page<$pages){
		$r.= sprintf('<li><a href="?p=%d">&gt;</a></li><li><a href="?p=%d">»</a></li>', $page+1, $pages);
	}
	$r.= '</ul>';
	return $r;
}
?>

Atzīstu, ir tādas, lietas, kuras kādreiz tikušas izdomātas un tiek lietotas vēl šodien. Tomer, ja kaut ko mēģina uztaisīt no šodienas skata punkta, loģiski – tas sanāk daudz ātrāk un vienkāršāk.

Kalendārs PHP stilā.

8
Jun
4

Protams, runa ir par vārda dienām. Vairākas reizes tas ir bijis vajadzīgs, katrreiz kaut kur meklēju, kopēju un beidzot tas piegriezās. Ņēmu kalendāru un drukāju (tas bija pagājšgad?), jo man šis kalendārs bija nepieciešams savā stilā. Derīgs čarsets, vārdi masīvā un vispār kārtība.

Ja tev arī vajag vārda dienu sarakstu, tad skripts lasot pilno rakstu.

Kā pasargāt sevi no SQL injekcijām

22
May
10

Mūžam vecā lieta, kad kāds aizmirsis pārbaudīt datus, pirms tos liek SQL pieprasījumā, un kāds cits ir atklājis šo ievainojamību. Kā tad maksimāli izvairīties no šādām problēmām?

Ir redzētas dažādas datubāžu pieprasījumu veidošanas klases, bet tā īsti nav sanācis izmantot nevienu. Tad nu lūk, kādas īsti ir priekšrocības mysql_query() iebāzt kādā citā funkcijā? Tādas, ka tā cita funkcija var darīt vēl šo to, piemēram, palīdzēt debug’ot kodu. Precīzāk, saskaitīt nosūtīto pieprasījumu skaitu, izpildes laiku un visu pārējo, ko vēlies redzēt.

Bet ne par to ir runa. Neturēšu sveci zem pūra un parādīšu, manuprāt, nozīmīgāko, kas man neļauj aizmirst, par datu drošību. Kveriju sastādu pēc printf() principa, nevis līmējot stringus. Pieprasījuma veidošana izskatīsies šādi:

$db->query("SELECT id FROM `tabula` WHERE lauks1=%d AND laiks2=%s AND lauks3=%.2f OR lauks4=NOW()", $var1, $var2, $var3);

Tālāko varat iedomāties paši.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function query($query){
	if(func_num_args()>1){
		$args = func_get_args();
		$query = call_user_func_array(array($this, 'make_args'), $args);
	}
	$this->queries[] = $query; // etc
	return mysql_query($query);
}
 
function make_args(){
	$args = func_get_args();
	$arr = array($args[0]);
	foreach($args as $arg){
		$arr[] = $arg==='' ? 'NULL' : ($this->is_numeric($arg) ? $arg : "'".mysql_real_escape_string($arg)."'"); // eskeipojam katru mainīgo, ja tas nepieciešams
	}
	return call_user_func_array('sprintf', $arr);
}
 
function is_numeric($what){
	return (!preg_match('/^\-?\d+(\.\d+)?$/D', $what) || preg_match('/^0\d+$/D', $what)) ? false : true;
}

Arī update funkciju esmu uztaisījis savu, kur padodu tikai masīvu ar atjaunojamajiem laukiem

$db->update('tabula', $id, array(
	'lauks1' => $var1,
	'lauks2' => $var2,
	'~lauks3' => 'NOW()' // SQL'iskas funkcijas nevajag apstrādāt
));

Un konstruējot pieprasījumu, apstrādājam mainīgos

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function update($table, (int)$id, $updates, $id_field = 'id'){
	$update = array();
	foreach($updates as $key=>$val){
		list($field, $value) = $this->process_pair($key, $val);
		$update[] = "$field=$value";
	}
	$update = implode(", ", $update);
	return $this->query("UPDATE `$table` SET $update WHERE $id_field=$id");
}
 
function process_pair($field, $value){
	$escape = true;
	if($field[0]=='~'){ // eskeipot mainīgo ?
		$escape = false;
		$field = substr($field, 1);
	}
	return array($field, ($value==='' ? 'NULL' : ($this->is_numeric($value) ? $value : "'".mysql_real_escape_string($value)."'")));
}

Rezultātā praktiski visi mainīgie tiks eskeipoti automātiski un aizmirst par mysql_real_escape_string() lietošanu būs gandrīz neiespējami. Tāpat man patīk arī sintakse, kur nav jālipina kopā stringi.

Jāatzīst, ka diezgan pasen kaut kur jau manīju šādu risinājumu, taču biju piemirsis un pirms pāris mēnešiem atcerējos, nolēmu, ka toreiz manītā ideja man tīri labi patīk un nu jau kādu laiku pats lietoju praksē.

Personas koda un IBAN validācija

14
Apr
4

Šie validācijas skripti gan vairāk attiecas uz mani pašu, jo tos tāpat var diezgan viegli atrast izmantojot tanti gūgli. Bet kāpēc man katru reizi meklēt, ja es varu tos pierakstīt un nākamreiz jau doties uz konkrētu vietu un nokopēt? (:

Personas kods:

1
2
3
4
5
6
function validate_pk($pk){
	$pk = preg_replace("/[^\d]/","",$pk);
	$calc = 1*$pk[0]+6*$pk[1]+3*$pk[2]+7*$pk[3]+9*$pk[4]+10*$pk[5]+5*$pk[6]+8*$pk[7]+4*$pk[8]+2*$pk[9];
	$checksum = (1101-$calc)%11;
	return $checksum==$pk[10];
}

IBAN (bankas konta numurs):

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
33
34
35
36
37
function validate_iban($str,$reformat=true,$debug=false){
	if($reformat){
		$str = preg_replace('/[\W_]+/','',strtoupper($str));
	}
	$errors = array();
	if(4>strlen($str) || strlen($str)>34){
		$errors[] = 'Invalid string length';
	}
	if(is_numeric($str[0]) || is_numeric($str[1])){
		$errors[] = 'Invalid chars at 0, 1';
	}
	if(!is_numeric($str[2]) || !is_numeric($str[3])){
		$errors[] = 'Invalid chars at 3, 4';
	}
	$ibanReplaceChars = range('A','Z');
	foreach(range(10,35) as $tempvalue){
		$ibanReplaceValues[]=strval($tempvalue);
	}
	$tmpIBAN = substr($str,4).substr($str,0,4);
	$tmpIBAN = str_replace($ibanReplaceChars,$ibanReplaceValues,$tmpIBAN);
	$tmpValue = intval(substr($tmpIBAN,0,1));
	for($i=1;$i<strlen($tmpIBAN);$i++){
		$tmpValue*= 10;
		$tmpValue+= intval(substr($tmpIBAN,$i,1));
		$tmpValue%= 97;
	}
	if($tmpValue!=1){
		$errors[] = 'Invalid checksum';
	}
	if(empty($errors)){
		return true;
	}
	if($debug){
		echo implode("\n", $errors);
	}
	return false;
}

Keša problēmu risināšana

27
Jan
0

Lielāku portālu izmaiņu veikšanai nepieciešams, lai lietotāja interneta pārlūkprogramma pieprasītu atjaunotos datus, kā zināms, brouzeriem patīk tos pieglabāt – kešot (cache) -, tādejādi paātrinot lapas ielādi sev un samazinot trafika lielumu mums.

Protams, varam likt pārlūkam pieprasīt pilnīgi visu no jauna, taču, tas paildzinās lapas ielādes laiku un mūsu trafiku, kas nebūs no tiem labākajiem risinājumiem.

Bet kā likt pārlūkam pa jaunu pieprasīt tikai izmainītos failus? Principā, ideja ļoti vienkārša. Nedosim nekādus header’us, bet liksim domāt, ka šis fails agrāk nemaz nav redzēts.

Pārlūkam interesē pilna faila adrese, tātad tiek ņemtas vērā arī GET vērtības. Neizteicos korekti, bet doma bija – pamainam vērtību, kas seko aiz jautājuma zīmes, piemēram, /css/layout.css?xxx. Taču šo vērtību neģerēsim katru reizi randomā, jo šādā gadījumā fails atkal tiktu pieprasīts pie katras lapas ielādes. Kā mainīgo vērtību padosim faila izmaiņu veikšanas laiku.

<link rel="stylesheet" href="/css/layout.css?<?=filemtime($_SERVER['DOCUMENT_ROOT'].'/css/layout.css');?>" type="text/css" media="screen" />

Kodā tas neizskatīsies smuki (ja tas tevi neuztrauc, tad tālāk vari nelasīt), šoreiz palīdzīgu roku var sniegt mod_rewrite. Mainīgo vērtību varam padot, nevis caur jautājuma zīmi, bet gan kā mapi, piemēram, /css/jan27/layout.css.

<link rel="stylesheet" href="/css/<?=strtolower(date("Mj",filemtime($_SERVER['DOCUMENT_ROOT'].'/css/layout.css')));?>/layout.css" type="text/css" media="screen" />

Ierakstu dalīšana pa lappusēm

24
Jan
21

Tēma šoreiz nav sareģīta, bet visur ir savs āķis.

Zināms, ka, lai izrēķinātu lappušu skaitu, jāzin kopējais ierakstu skaits, tātad divi pieprasījumi uz datubāzi:

  1. Iegūstam nepieciešamo skaitu ar ierakstiem
  2. Iegūstam kopējo ierakstu skaitu

Bet kur tad optimizācija? Un ja vēl nepieciešams liels skaits dinamiski ģenerētu filtru? Būs jāveido divi gandrīz identiski pieprasījumi – viens ar limitu, viens bez.

Es piedāvāju izmantot vienu no ne tik slavenajām MySQL funkcijām – SQL_CALC_FOUND_ROWS un FOUND_ROWS(). Pieprasījums un tā apstrāde, manā gadījumā, izskatīsies šādi:

1
2
3
4
5
6
7
8
9
10
11
12
<?
  $perpage=10; // ieraksti vienā lappusē
  $_LIMIT=(!empty($_GET['p']) && $_GET['p']>1)?($_GET['p']*$perpage)-$perpage:0; // izrēķinam limita sākuma pozīciju, atkarīgā no atvērtās lappuses, kas padota kā ?p=X
  $_LIMIT.=", ".$perpage;
  $sql="SELECT SQL_CALC_FOUND_ROWS * FROM `tabula` LIMIT ".$_LIMIT;
  $res=mysql_query($sql);
  $count=mysql_fetch_object(mysql_query("SELECT FOUND_ROWS() as c"));
  while($row=mysql_fetch_object($res)){
    var_dump($row);
  }
  $pages=splittopages($count->c,$perpage);
?>

Funkcija, kura izrēķinās lappušu skaitu. Pieejamās lappuses tiek saliktas masīvā, lai būtu vienkāršāk izveidot pogas “Nākamā lappuse” un “Iepriekšējā lappuse” – atliek tikai pārbaudīt vai masīvā eksistē ieraksts ar atbilstošu atslēgu.

1
2
3
4
5
6
7
8
9
10
11
<?
  function splittopages($count,$perpage){
    $pagescount=ceil($count/$perpage);
      $pages=array();
      if($pagescount<2){ return $pages; }
        for($i=1;$i<=$pagescount;$i++){
        $pages[]=$i;
      }
    return $pages;
  }
?>

Lappušu izvade.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  if($_GET['p']<2){ $_GET['p']=1; } // definēsim lappusi paši, ja tā vēl nav definēta
  $now=array_search($_GET['p'],$pages); // atvērtā lappuse
  $prev=$now-1;
  $next=$now+1;
  if(array_key_exists($prev,$pages)){
    echo '<a href="?p='.$pages[$prev].'">Iepriekšējā lappuse</a>';
  }
  foreach($pages as $value){
    $active=$_GET['p']==$value?' class="active"':''; // atzīmējam atvērto lappusi
    echo '<a href="?p='.$value.'"'.$active.'>'.$value.'</a>';
  }
  if(array_key_exists($next,$pages)){
    echo '<a href="?p='.$pages[$next].'">Nākamā lappuse</a>';
  }
?>

Lielākais ieguvums izmantojot šādu risinājumu ir tāds, ka nav jāsūta vēl viens praktiski identisks pieprasījums uz datubāzi, ierakstu skaits jau tiek nokešots MySQL’ā.
Bez liekiem if’iem tiek pie nākamās un iepriekšējās lappuses.

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 :)

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.

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);
?>