Jak wydobyć kod authinfo domeny od rejestratora.

Sierpień 10th, 2010 Zbigniew Heintze 7 comments

Dawno nie pisałem. Przyczyn tego stanu rzeczy oraz dłuższej niedostępności mojego bloga jest kilka, ale pra przyczyną było to, że kilka lat temu zaufałem firmie.

„Info-Cal” Roman Trziszka
ul. Chludowska 387 lok. 9
62-003 Biedrusko

NIP: 778-100-71-00, Regon: 630002043

Nie jestem zbyt wymagającym klientem – nie narzucam się zbytnio, nie robię awantury kiedy serwer nie działa przez kilka godzin, nie żądam zakręconych rozwiązań i 24 godzinnego suportu. Jedyne czego nienawidzę to kiedy robi się ze mnie idiotę, a ponieważ obsłudze serwera cal.pl zdarzyło się kilka razy próbować wmówić mi, że wina niedziałającej aplikacji leży po mojej stronie podczas gdy były to najczęściej niedopatrzenia administratorów grzebiących w konfiguracji serwera postanowiłem rozstać się z hostingiem na cal.pl.

Ale jak tu się uwolnić od niechcianej miłości? Cały proces przypominał mi próbę przeprowadzenia rozwodu z żoną, która na pożegnanie ima się wszelkich sposobów aby wyrwać dla siebie co się jeszcze da.

Z backupami baz danych i oskryptowania stron nie było problemu. Schody zaczęły się kiedy poprosiłem o wydanie kodów authinfo do moich domen w tym tej, pod którą można znaleźć niniejszy blog.

Wydawać by się mogło, że przeniesienie domeny od jednego rejestratora do innego to tylko formalność. Wystarczy poprosić o kod authinfo podmiot, który dotychczas rejestrował domeny w naszym imieniu, a następnie przesłać je – zazwyczaj za pośrednictwem formularza na stronie internetowej – nowemu rejestratorowi, a on już za nas załatwi wszystkie sprawy formalne i techniczne. Tymczasem chęć przeniesienia domen w inne miejsce kłóci się z interesem naszego dotychczasowego rejestratora, który tak jak w moim przypadku robi wszystko aby cały proces wydłużyć, a najlepiej zniechęcić klienta do całej operacji.

Pan Roman Trziszka poszedł w formalizm. Wydanie kodu authinfo w firmie INFO-CAL wymaga wysłania stosownego wniosku wraz z kserokopiami odpowiednich dokumentów przy czym nie są one szczegółowo wymienione. Można było skorzystać z faksa, ale ja nauczony doświadczeniem wolałem wysłać list za potwierdzeniem odbioru. Po czterech dniach otrzymałem lakoniczną odpowiedź, że moje wnioski zostały odrzucone a powodem był „brak wymaganych dokumentów jako załączników”. Po wymianie kilku maili dowiedziałem się, że abonentem domen jest osoba fizyczna, a nie osoba prawna, a poza tym nie zgadza się adres i że powinienem wysłać kserokopie dowodu osobistego, a nie dokumenty firmy. Ja się pytam od kiedy jednoosobowa działalność gospodarcza ma osobowość prawną? Adres tzw. „zakładu głównego” rzeczywiście nie pokrywał się z moim poprzednim adresem zamieszkania jednak w przesłanym „Zaświadczeniu o dokonaniu wpisu do ewidencji działalności gospodarczej” można było łatwo odnaleźć drugi adres wykonywania działalności gospodarczej zgodny z tym zarejestrowanym w bazie WHOIS. Moja argumentacja została podsumowana krótkim stwierdzeniem, że wnioski zaraz po odrzuceniu są niszczone i nawet gdyby pracownicy firmy INFO-CAL chcieli to fizycznie nie mogą tego zweryfikować dlatego proszony jestem o wysłanie kolejnych wniosków wraz z kserokopią dowodu osobistego.

Muszę powiedzieć, że krew mnie wtedy zalała. W międzyczasie ożeniłem się, przeprowadziłem i wymieniłem dowód osobisty – zawsze twierdziłem, że małżeństwo jest źródłem wszelkich kłopotów – jednak nie straciłem głowy do końca bo się nie przemeldowałem i w moim dowodzie osobistym był wciąż ten sam adres co kiedyś. Mogłem wysłać kolejne wnioski, ale wyczytałem na stronie NASK informację zgodnie z którą:

Na żądanie Abonenta Partner obsługujący nazwę domeny zobowiązany jest niezwłocznie wydać kod authinfo, który umożliwi przeniesienie obsługi. Partner nie może uzależniać wydania kodu od uprzedniego spełnienia dodatkowych warunków.

Zażądałem więc wydania kodów authinfo i zagroziłem, że w przypadku nie spełnienia mojej prośby popełnię stosowny dokument do Rzecznika Praw Konsumenta oraz do NASK. Oczywiście Pan Roman Trziszka się nie przejął stwierdzając jedynie, że on wyda kody tylko, że musi mieć pewność co do tożsamości abonenta domen. Jakoś potwierdzenie mojej tożsamości nie było wymagane przy corocznym przedłużaniu ważności domeny, przy zmianie danych osobowych co uczyniłem przy okazji założenia działalności gospodarczej przy okazji pobierania ze strony cal.pl dokumentów finansowych (faktur). Potwierdzenie mojej tożsamości nie było wymagane w całym procesie zarządzania kontem www, aż do tego momentu.

Jako programista jestem osobą leniwą, a do tego z natury ugodową. Wysłałem w końcu ponownie wnioski (oczywiście za potwierdzeniem odbioru). Kiedy po 7 dniach od otrzymania potwierdzenia odbioru nie otrzymałem odpowiedzi na moje wnioski napisałem upominającego maila. Przedstawiciel firmy INFO-CAL – dodam na marginesie, że pod żadnym z mail otrzymanych od obsługi cal.pl nigdy nie znalazł się jakikolwiek imienny podpis – udzielił mi odpowiedzi, że jeszcze wniosków nie otrzymali, a jeśli nawet to na odpowiedź na wnioski pisemne mają 20 dni, i że jeżeli zależy mi na czasie to powinienem wysłać wnioski faksem.

Pokornie wysłałem wnioski faksem. Nikt nie zgadnie jaką otrzymałem odpowiedź? „Wnioski odrzucone z powodu nieczytelności.” Ręce mi opadły i na prawdę byłem już gotów napisać tego cholernego paszkwila do Rzecznika Praw Konsumenta oraz do NASK. Przestałem wymieniać korespondencję z INFO-CAL bo mijało się to z celem. Powiedziałem sobie w duchu, że nie dam zarobić już ani grosza tej „cholernej hienie”. Wykupiłem opcje na swoje własne domeny i czekałem cierpliwie kiedy wygasną.

Jakiś tydzień przed wygaśnięciem pierwszej z domen otrzymałem wiadomość od firmy Pana Romana Trziszki, że kody authinfo do domen zostaną wydane, za wyjątkiem tej najbliższej wygaśnięciu, do której kod zostanie wydany ale pod warunkiem jej wcześniejszego przedłużenia, zgodnie z pkt. 6.12 regulaminu.

6.12. Administrator może odmówić wydania kodu autoryzacyjnego domeny ( kod AuthInfo ) w przypadku domen wygasających w przeciągu 30 dni od daty otrzymania wniosku oraz do 30 dni po wykonaniu odnowienia domeny.

Wydanie kodów tym razem nie wymagało wysyłania żadnych szczególnych wniosków ani załączników, a jedynie wysłania maila z prośbą na adres domeny@consultingservice.pl??? Wysłałem i otrzymałem na drugi dzień kody do wszystkich moich domen.

Nie opiszę co czułem, kiedy się dowiedziałem, że faktycznym rejestratorem moich domen nie jest „Info-Cal” Roman Trziszka.

Później znalazłem w sieci wpis Damiana Nowaka pt. Prawa właściciela domeny – transfer i wydanie kodu authinfo, który może przydać się kiedyś każdemu posiadaczowi choćby jednej domeny. Żałuję, że nie natrafiłem na niego wcześniej – zaoszczędziłbym sobie wiele nerwów.

Firma „Info-Cal” Pana Romana Trziszki świadomie wprowadziła mnie w błąd w celu uzyskania korzyści materialnych, nie przestrzega regulaminów NASK, których jest już na chwilę obecną pełnoprawnym partnerem, a na dodatek dopuściła się naruszenia ustawy o ochronie danych osobowych. Nie będę się już rozwodził na temat niekompetencji administratorów serwerów cal.pl. To temat na kolejny wpis. Wszystkim obecnym i potencjalnym klientom wyżej wspomnianej firmy szczerze odradzam korzystania z jej usług.

Kategorie:Priv Tagi:

Bazaar uzupełnieniem SVN-a

Czerwiec 11th, 2010 Zbigniew Heintze Brak komentarzy

Subversion – jeden model pracy

Najbardziej popularnym systemem wersjonowania jest Subversion. Został on zaprojektowany do pracy w sposób scentralizowany. Działa to tak, że gdzieś na serwerze znajduje się centralne repozytorium z którego programista pobiera kopię roboczą na swój lokalny komputer. Dokonuje modyfikacji plików po czym zatwierdza dokonane zmiany w repozytorium centralnym. Taki model pracy ma swoje zalety jednak zdarzają się sytuacje kiedy przydała by się lokalna wersja repozytorium. Poczciwy SVN nie daje jednak możliwości pracy w sposób rozproszony co jest jego wielką słabością w stosunku do np. Gita czy Bazaar-a, które dzięki swojej elastycznej architekturze oferują wiele przeróżnych sposobów organizacji pracy z repozytorium.

Modele pracy są jednym z wielu argumentów, dla których warto rozważyć przesiadkę na inny system kontroli wersji. Polecam zapoznać się z artykułami Why Switch to Bazaar? – Any Workflow albo Workflows – Bazaar Version Control oraz Why Git is Better than X – Any Workflow.

Ja pracuję już kilka lat z Subversion i większość firm z którymi współpracuję lub też współpracowałem też używa SVN. Dlatego decyzja o zmianie systemu wersjonowania najczęściej nie leży w mojej gestii.

Co mogę zatem zrobić? Zarówno Bazaar (bzr-svn) jak i Git (git-svn) mają narzędzia umożliwiające współpracę z Subversion.

Po co łączyć Subversion z Bazaarem lub Gitem

Model pracy rozproszonej oferuje kilka możliwości stanowiących doskonałe uzupełnienie modelu scentralizowanego.

  • Słabe połączenie internetowe albo jego brak nie jest problemem ponieważ wszelkie zmiany dokonywane są lokalnie. Połączenie z serwerem centralnym potrzebne jest jedynie raz na jakiś czas.
  • Niezależne repozytorium, odseparowane i nienarażone na zmiany czynione przez innych użytkowników daje możliwość eksperymentowania. Dokonane zmiany w przypadku powodzenia można później scalić z główną gałęzią lub też usunąć nie zaśmiecając historii zmian centralnego repozytorium.
  • Można ustalić procedurę zgodnie z którą zmiany dokonane w projekcie przez developera trafiają najpierw do osoby nadzorującej projekt, która je sprawdza, testuje i dopiero po akceptacji pcha da SVN-a. W ten sposób do centralnego repozytorium trafią jedynie zmiany stabilne.
  • Warto też wspomnieć o takim prozaicznym powodzie jak brak upierdliwych katalogów „.svn” w katalogu roboczym projektu – małe a cieszy :D .

Praca z Bazaarem jako uzupełnieniem Subversion

Importowanie repozytorium

Ja wybrałem Bazaar z uwagi na moje większe doświadcznie z tym systemem kontroli wersji.

Dla tych, którzy nie mieli jeszcze styczności z Bazaarem proponuję na start prosty tutorial Bazaar in five minutes. Jeśli chodzi o naukę to Bazaar ma tę przewagę nad Gite, że większość jego komend jest identyczna z tymi znanymi z SVN.

Jeśli nie mamy jeszcze zainstalowanego Bazaara (bzr) oraz wtyczki umożliwiającej współpracę z Subversion bzr-svn to w przypadku Ubuntu wystarczy jedynie pobrać wyżej wspomniane z repozytorium i zainstalować.

sudo apt-get install bzr bzr-svn

W przytoczonym wyżej tutorialu nowe repozytorium tworzy się poprzez komendę bzr init. W tym przypadku nie ma takiej potrzeby. Aby „zaimportować” repozytorium SVN do Bazaara należy utworzyć tzw. brancha. Zakładam że znajdujemy się w katalogu roboczym, w którym trzymamy projekty (workspace). Wywołujemy komendę bzr branch i podajemy jako parametry url repozytorium svn oraz nazwę katalogu jaki zostanie stworzony na naszym komputerze i w którym zostanie utworzone lokalne repozytorium Bazaara.

bzr branch svn+http://svn-repository.example.com/project/trunk ./project

Od tego momentu można już pracować z Bazaarem. Dostępna jest pełna historia zmian i jakby się uprzeć to można zapomnieć o SVN-ie ;) (choć do właściwego importu SVN do Bazaar służy komenda bzr svn-import) Dostępne mamy zarówno narzędzia konsolowe, jak też całą kolekcję GUI z których niejako firmowym jest multoplatformowy Bazaar Explorer. Fanom Eclipse polecam z kolei plugin do obsługi Bazaara, który niczym nie ustępuje swojemu odpowiednikowi dla Subversion.

Pracujemy w ten sposób, że wszelkie zmiany w plikach zatwierdzamy (commit) do lokalnego repozytorium. Kiedy zmiany w projekcie przyjmują już stabilną postać jesteśmy gotowi do zarejestrowania wprowadzonych poprawek w centralnym repozytorium SVN. Zanim to jednak zrobimy należy najpierw sprawdzić czy od czasu ostatniego pobrania zmian z SVN coś się nie zmieniło. W końcu najczęściej nie pracujemy sami. Wchodzimy do katalogu naszego projektu i wywołujemy:

Warto sprawdzić czy coś się zmieniło?

bzr pull svn+http://svn-repository.example.com/project/trunk

Jeśli pracujesz w zespole, a poprawka którą miałeś zrobić nie była mała to najprawdopodobniej otrzymasz komunikat, że w repozytorium dokonano zmian. Trzeba je będzie sprawdzić, scalić z lokalnymi zmianami i ponownie zatwierdzić. Bazaar podpowie Ci co masz zrobić.

bzr: ERROR: These branches have diverged. Use the missing command to see how.
Use the merge command to reconcile them.

Scalanie różnic jest proste

Jeśli inni developerzy nie edytowali tych samych plików co ty to zazwyczaj wystarczy:

Do podejrzenia różnic

bzr missing

Do scalenia zmian

bzr merge

Następnie przydałoby się sprawdzić jakie pliki różnią się względem lokalnego repozytorium po scaleniu ze zmianami dokonanymi w repozytorium centralnym

bzr status

Po ich zatwierdzeniu

bzr commit -m 'Treść komunikatu'

Zostaje już tylko wysłanie wszystkiego do svn.

bzr push svn+http://svn-repository.example.com/project/trunk



UWAGA! append_revisions_only error



W tym momencie najprawdopodobniej wyskoczy Ci mały Zonk i otrzymasz taki niemiły komunikat

Using saved push location: svn+http://svn-repository.example.com/project/trunk
bzr: ERROR: Operation denied because it would change the mainline history. Set the append_revisions_only setting to False on branch "svn+http://svn-repository.example.com/project/trunk" to allow the mainline to change.

Niestety komunikat Bazaar nie jest w tym wypadku wyczerpujący gdyż nic nie mówi na temat tego gdzie ustawić append_revisions_only na false.

W Ubuntu wyedytuj plik ~/.bazaar/subversion.conf i dodaj wspomnianą dyrektywę pod adresem repozytorium SVN

[4ef181b9-d188-42c4-ae88-58g6dfg8760b]
locations = svn+http://svn-repository.example.com/project/trunk
append_revisions_only = False

To powinno załatwić sprawę.

Uwaga konflikt!

To był optymistyczny scenariusz. W mniej pomyślnej sytuacji dokonasz zmian w tym samym pliku w którym ktoś inny grzebał i to najprawdopodobniej w tych samych liniach. Automat tego nie rozwiąże. Załóżmy, że chodzi o plik „foo.py”. Pojawia się konflikt a problematyczny plik doznaje cudownego rozmnożenia.

  1. foo.py.BASE – plik w wersji pozbawionej zmian powodujących konflikt (w svn foo.py.rOLDREV)
  2. foo.py.OTHER – plik ze zmianami dokonanymi przez innego użytkownika (w svn foo.py.rNEWREV)
  3. foo.py.THIS – plik z moimi lokalnymi zmianami (w svn foo.py.mine)
  4. foo.py – zawiera to samo co foo.py.THIS

Kilka słów od Kdiff3 – bez niego moje życie było by o wiele bardziej skomplikowane

Każdy ma swoje ulubione narzędzie do scalania różnic. Ja preferuję Kdiff3 – dostępny na Linuksa i Windowsa. Mimo, że zarówno Eclipse jak i Bazaar Explorer mają swoje narzędzia do porównywania zmian ja staram się użyć Kdiff3 którego interfejs jest mi dobrze znany.

Edycja konfliktu przy użyciu Kdiff3 wymaga wywołania w konsoli komendy

kdiff3 foo.py.BASE foo.py.OTHER foo.py.THIS -o foo.py

Oczywiście nie wszyscy lubią konsolę. Aby np. Bazaar Explorer korzystał z Kdiff3 należy wyedytować plik ~/.bazaar/bazaar.conf i w sekcji DEFAULT dodać.

external_merge = kdiff3 %b %o %t -o %r

Jako ciekawostkę kierując się zawodową uprzejmością podaję też sposób wywołania tortoisemerge.

external_merge = tortoisemerge /base:%b /theirs:%o /mine:%t /merged:%r

Kdiff3 można też zintegrować z Eclipse jednak opcję taką znalazłem jedynie dla Subversion. Należy otworzyć Preferencje->Team->Diff/Merge. W sekcji „Conflict Resolution Program” wybrać opcję „External” i wskazać gdzie leży Kdiff3 (u mnie /usr/bin/kdiff3). W polu parameters należy podać

${base} ${yours} ${theirs}  -o ${merged}

Rozwiązaniem konfliktu należy się pochwalić

Po ręcznym rozstrzygnięciu konfliktów należy Bazaar poinformować o tym – analogicznie jak w svn.

bzr resolve foo.py

Komenda „resolve” usuwa przy okazji pliki foo.py.BASE, foo.py.OTHER oraz foo.py.THIS. Teraz wystarczy już tylko zatwierdzić zmiany (commit) oraz pchnąć do centralnego repozytorium (push).

Dobra rada na koniec

Bazaar czy Git to systemy kontroli wersji stworzone do pracy rozproszonej oraz dopracowane pod kątem łączenia osobnych repozytoriów. Mają pod tym względem znaczną przewagę nad Subversion. Model pracy będący mixem korzystającym z rozproszonego repozytorium np. Bazaar oraz centralnego SVN ma swoje zalety jednak stanowi dodatkowy narzut pracy związany z koniecznością dublowania pewnych czynności. Nie należy na siłę wdrażać rozwiązań, które nie są efektywne lub wręcz zbędne. Dlatego jeśli w firmie używającej Subversion stosuje się dopracowane procedury zatwierdzania zmian w repozytorium, nie ma problemów z połączeniem, a modyfikacje w projekcie nie mają charakteru rewolucji będącej jednym wielkim eksperymentem wymagającym tworzenie piaskownicy, być może funkcjonalność Subversion jest w zupełności wystarczająca.

Kategorie:Systemy kontroli wersji Tagi:

PHP 5.3 – wywołanie array_multisort za pośrednictwem call_user_func_array

Czerwiec 8th, 2010 Zbigniew Heintze Brak komentarzy

Chcąc dostosować swój kod do wersji PHP 5.3, tak aby wykonywał się bezproblemowo z uwzględnieniem błędów STRICT natrafiłem na taki drobny szczegół. Swego czasu dodałem do manuala funkcji array_multisort na php.net taką drobną [notkę zawierającą implementację funkcji ułatwiającej sortowanie wyników zapytań sql-owych] (http://usphp.com/manual/en/function.array-multisort.php#87268).

Chcąc ją dzisiaj użyć dostałem na twarz warning-a „Parameter 2 to array_multisort() expected to be a reference, value given”.

Załóżmy, że miałem następujące dane.

$data = array(
	0 => array (
		'id' => '1',
		'name' => 'Rodzaje',
	),
	1 =>
	array (
		'id' => '2',
		'name' => 'Kategorie',
	),
	2 =>
	array (
		'id' => '3',
		'name' => 'Statusy',
	),
	3 =>
	array (
		'id' => '4',
		'name' => 'Kolory',
	),
);

Aby posortować tę tablicę według kolumny „name” wywołałem wspomnianą funkcję w następujący sposób

sortDbResult($data, 'name', SORT_ASC, SORT_STRING);

Przyjrzałem się problematycznej linii i zobaczyłem, że wywołuję funkcję array_multisort przy pomocy funkcji call_user_func_array, do której parametry przekazuję za pośrednictwem tablicy.

call_user_func_array('array_multisort', $_params);

W moim przypadku zmienna $_params miała następującą zawartość

array(
0 => &array (
	0 => 'Rodzaje',
	1 => 'Kategorie',
	2 => 'Statusy',
	3 => 'Kolory',
),
1 => 2,
2 => 4,
3 => array(
	0 => array (
		'id' => '1',
		'name' => 'Rodzaje',
	),
	1 =>
	array (
		'id' => '2',
		'name' => 'Kategorie',
	),
	2 =>
	array (
		'id' => '3',
		'name' => 'Statusy',
	),
	3 =>
	array (
		'id' => '4',
		'name' => 'Kolory',
	),
));

Pomyślałem sobie o co chodzi z tym błędem w końcu drugi parametr funkcji array_multisort to w moim przypadku wartość stałej SORT_ASC czyli 2. Przeprowadziłem mały eksperyment i wywołałem funkcję array_multisort bezpośrednio.

$data_1 = array (
	0 => 'Rodzaje',
	1 => 'Kategorie',
	2 => 'Statusy',
	3 => 'Kolory',
);
 
$data_2 = array(
	0 => array (
		'id' => '1',
		'name' => 'Rodzaje',
	),
	1 =>
	array (
		'id' => '2',
		'name' => 'Kategorie',
	),
	2 =>
	array (
		'id' => '3',
		'name' => 'Statusy',
	),
	3 =>
	array (
		'id' => '4',
		'name' => 'Kolory',
	),
);
array_multisort($data_1, SORT_ASC, SORT_STRING, $data_2);
 
var_dump($data_2);

Zadziałało. Tablica $_data2 została posortowana prawidłowo.

call_user_func_array('array_multisort',  array(&$data_1, SORT_ASC, SORT_STRING, &$data_2));

Powyższy kod również wykonał się nie zwracając żadnych komunikatów błędów.

$params = array(&$data_1, SORT_ASC, SORT_STRING, &$data_2);
call_user_func_array('array_multisort',  $params);

Wykonanie powyższego kodu kończy się już niestety warningiem. Aby się go pozbyć trzeba użyć małego obejścia i przypisać wartości stałych do zmiennych a następnie przekazać je do tablicy przy pomocy referencji.

$o = SORT_ASC;
$v = SORT_STRING;
$params = array(&$data_1, &$o, &$v, &$data_2);
call_user_func_array('array_multisort', $params);

W tym wypadku nie działa ukrywanie błędów. Funkcja array_multisort po prostu nie zadziała prawidłowo.

Poprawiona funkcja sortDbResult wygląda następująco:

/**
 * Sort DB result
 *
 * @param array $data Result of sql query as associative array
 *
 * Rest of parameters are optional
 * [, string $name  [, mixed $name or $order  [, mixed $name or $mode]]]
 * $name string - column name i database table
 * $order integer - sorting direction ascending (SORT_ASC) or descending (SORT_DESC)
 * $mode integer - sorting mode (SORT_REGULAR, SORT_STRING, SORT_NUMERIC)
 *
 * 
 *  $i,
 *                      'first_name' => sprintf('first_name_%s', rand(1, 9)),
 *                      'last_name' => sprintf('last_name_%s', rand(1, 9)),
 *                      'date' => date('Y-m-d', rand(0, time()))
 *                  );
 * }
 * $data = sortDbResult($data, 'date', SORT_DESC, SORT_NUMERIC, 'id');
 * var_dump($data);
 * $data = sortDbResult($data, 'last_name', SORT_ASC, SORT_STRING, 'first_name', SORT_ASC, SORT_STRING);    
 * var_dump($data);
 * ?>
 * 
 *
 * @return array $data - Sorted data
 */

function sortDbResult(array $data /*$name, $order, $mode*/) {
	$_argList = func_get_args();
	$_data = array_shift($_argList);
	if (empty($_data)) {
		return $_data;
	}
	$_max = count($_argList);
	$_params = array();
	$_cols = array();
	$_rules = array();
	for ($_i = 0; $_i < $_max; $_i += 3)
	{
		$_name = (string) $_argList[$_i];
		if (!in_array($_name, array_keys(current($_data)))) {
			continue;
		}
		if (!isset($_argList[($_i + 1)]) || is_string($_argList[($_i + 1)])) {
			$_order = SORT_ASC;
			$_mode = SORT_REGULAR;
			$_i -= 2;
		} else if (3 > $_argList[($_i + 1)]) {
			$_order = SORT_ASC;
			$_mode = $_argList[($_i + 1)];
			$_i--;
		} else {
			$_order = $_argList[($_i + 1)] == SORT_ASC ? SORT_ASC : SORT_DESC;
			if (!isset($_argList[($_i + 2)]) || is_string($_argList[($_i + 2)])) {
				$_mode = SORT_REGULAR;
				$_i--;
			} else {
				$_mode = $_argList[($_i + 2)];
			}
		}
		$_mode = $_mode != SORT_NUMERIC
					? $_argList[($_i + 2)] != SORT_STRING ? SORT_REGULAR : SORT_STRING
					: SORT_NUMERIC;
		// references below required from PHP 5.3
		$_rules[] = array('name' => $_name, 'order' => &$_order, 'mode' => &$_mode);
	}
	foreach ($_data as $_k => $_row) {
		foreach ($_rules as $_rule) {
			if (!isset($_cols[$_rule['name']])) {
				$_cols[$_rule['name']] = array();
				$_params[] = &$_cols[$_rule['name']];
				// references below required from PHP 5.3
				$_params[] = &$_rule['order'];
				$_params[] = &$_rule['mode'];
			}
			$_cols[$_rule['name']][$_k] = $_row[$_rule['name']];
		}
	}
	$_params[] = &$_data;
	call_user_func_array('array_multisort', $_params);
	return $_data;
}
Kategorie:PHP Tagi:

Instalacja (downgrade) php 5.2.x w Ubuntu 10.04 Lucid

Maj 13th, 2010 Zbigniew Heintze 2 comments

W końcu zdecydowałem się zaktualizować Ubuntu do nowszej wersji 10.04. Ku mojemu zaskoczeniu upgradowi uległ też PHP do wersji 5.3. Nie jest to przeze mnie koniecznie porządane w tym momęcie gdyż mam masę projektów, które nie zadziałają (jeszcze) z PHP w najnowszej wersji. Dlatego koniecznym stał sie downgrade do wersji 5.2. Na necie można znaleść wiele wskazówek jak tego dokonać.

Ja początkowo skorzystałem z artykułu pt. Install (downgrade) php 5.2.x in Ubuntu 10.04 Lucid. Niestety PHP po restarcie Apacha się nie odpalił. Ponieważ czasu miałem mało, nie zagłębiałem się w przyczynę niepowodzenia. Poszukałem i na jednym z forów o Ubuntu znalazłem gotowy skrypt bash-a.

#!/bin/bash
# by Ruben Barkow (rubo77) http://www.entikey.z11.de/
 
# Originally Posted by Bachstelze http://ubuntuforums.org/showthread.php?p=9080474#post9080474
# OK, here's how to do the Apt magic to get PHP packages from the karmic repositories:
 
echo "Am I root?  "
if [ "$(whoami &2>/dev/null)" != "root" ] && [ "$(id -un &2>/dev/null)" != "root" ] ; then
  echo "  NO!
 
Error: You must be root to run this script.
Enter
sudo su
"
  exit 1
fi
echo "  OK";
 
 
# finish all apt-problems:
apt-get -f install
 
# remove all your existing PHP packages. You can list them with dpkg -l| grep php
PHPLIST=$(for i in $(dpkg -l | grep php|awk '{ print $2 }' ); do echo $i; done)
echo these pachets will be removed: $PHPLIST 
# you need not to purge, if you have upgraded from karmic:
aptitude remove $PHPLIST
# on a fresh install, you need purge:
# aptitude remove --purge $PHPLIST
 
 
#Create a file each in /etc/apt/preferences.d like this (call it for example /etc/apt/preferences.d/php5_2);
#
#Package: php5
#Pin: release a=karmic
#Pin-Priority: 991
#
#The big problem is that wildcards don't work, so you will need one such stanza for each PHP package you want to pull from karmic:
 
echo ''>/etc/apt/preferences.d/php5_2
for i in $PHPLIST ; do echo "Package: $i
Pin: release a=karmic
Pin-Priority: 991
">>/etc/apt/preferences.d/php5_2; done
 
# duplicate your existing sources.list replacing lucid with karmic and save it in sources.list.d:
#sed s/lucid/karmic/g /etc/apt/sources.list | sudo tee /etc/apt/sources.list.d/karmic.list
 
# better exactly only the needed sources, cause otherwise you can get a cachsize problem:
echo "# needed sources vor php5.2:
deb http://de.archive.ubuntu.com/ubuntu/ karmic main restricted
deb-src http://de.archive.ubuntu.com/ubuntu/ karmic main restricted
 
deb http://de.archive.ubuntu.com/ubuntu/ karmic-updates main restricted
deb-src http://de.archive.ubuntu.com/ubuntu/ karmic-updates main restricted
 
deb http://de.archive.ubuntu.com/ubuntu/ karmic universe
deb-src http://de.archive.ubuntu.com/ubuntu/ karmic universe
deb http://de.archive.ubuntu.com/ubuntu/ karmic-updates universe
deb-src http://de.archive.ubuntu.com/ubuntu/ karmic-updates universe
 
deb http://de.archive.ubuntu.com/ubuntu/ karmic multiverse
deb-src http://de.archive.ubuntu.com/ubuntu/ karmic multiverse
deb http://de.archive.ubuntu.com/ubuntu/ karmic-updates multiverse
deb-src http://de.archive.ubuntu.com/ubuntu/ karmic-updates multiverse
 
deb http://security.ubuntu.com/ubuntu karmic-security main restricted
deb-src http://security.ubuntu.com/ubuntu karmic-security main restricted
deb http://security.ubuntu.com/ubuntu karmic-security universe
deb-src http://security.ubuntu.com/ubuntu karmic-security universe
deb http://security.ubuntu.com/ubuntu karmic-security multiverse
deb-src http://security.ubuntu.com/ubuntu karmic-security multiverse
" >> /etc/apt/sources.list.d/karmic.list
 
aptitude update
 
apache2ctl restart
 
echo install new from karmic:
aptitude -t karmic install $PHPLIST
 
# at the end retry the modul libapache2-mod-php5 in case it didn't work the first time:
aptitude -t karmic install libapache2-mod-php5
 
apache2ctl restart

Powyższy kod wystarczy zapisać w pliku o dowolnej nazwie np. phpdowngrade.sh, nadac mu prawa wykonalności

chmod +x ./phpdowngrade.sh

… i odpalić.

UWAGA! Aktualizacja PHP przez Synaptica przywróci nam z powrotem wersję 5.3. Doinstalowywanie wszelkich dodatków powinniśmy wykonywać z uwzględnieniem wydania. Najprościej to zrobić uzywając konsolowego programu aptitude.

sudo aptitude -t karmic install php5-mysql
sudo aptitude -t karmic install phpmyadmin
Kategorie:GNOME Tagi:

Motorola Milestone

Nareszcie moja. Czekalem dlugo, ale bylo warto. Moje pierwsze wrazenie kiedy dostalem go w swoje rece, to zaklopotanie. Wczesniej nie mialem aparatu z pelna klawiatura „qwerty” nie mowiac juz o ekranie dotykowym. Trzeba siege bylo nauczyc obslugiwac te piekielna maszyne.

Mysle ze wybor telefonu z fizyczna klawiatura byl dobrym pomyslem. Probowalem pisac na wirtualnej, ale bylo to mniej wygodne i do tego ograniczalo wielkosc ekranu. Moim skromnym zdaniem cztery podstawowe przyciski tj. „powrot”, „ustawienia”, „home” i „szukaj” tez mogly by byc fizyczne – tak jak w G1.

Ekran dotykowy to rewelacja tylko te slady paluchow widoczne zwlaszcza pod swiatlo… Chcac byc obiektywnym musze jednak stwierdzic, ze dla osoby czesto odbierajacej telefon, a do tego jeszcze robiacej to w malo sprzyjajacych warunkach („w biegu”, w samochodzie, jedna reka) aparat z ekranem dotykowym nie jest najlepszym rozwiazaniem. Obsluga takiego telefonu wymaga patrzenia na ekran i dosc precyzyjnych ruchow do tego rozmiar fona nie ulatwia sprawy. Inna kwestia jest pojemnosc baterii, ktora wymaga codziennego ladowania. Z drugiej strony mozliwosci jakie daje android warte sa rozwazenia opcji posiadania dwoch telefonow.

Mam to cacko zaledwie tydzien. Do czego zdazylem w Tym czasie uzyc telefonu? – zdobilem pare fajnych fotek i kilka filmikow na komunii chrzesniaka mojej zony – na wyjazd do Norymbergi nie zdazylem sciagnanc map do nawigacji bo kupilem telefon dzien przed wyjazdem, ale w jezdzie po Poznaniu aplikacja motoroli swietnie sie sprawdzila – zsynchronizowalem swoje kontakty z kontem na gmailu oraz facebooku – odebralem poczte z 3 skrzynek mailowych, oraz wyslalem email do kilku znajomych – dodalem kilka wpisow do kalendarza google – wgralem kilkanascie mp3-jek oraz innych plikow korzystajac z aplikacji motoroli, a takze poprzez ftp lub przegladarke internetowa (zarowno pod Windowsem, jak i Linuksem) – wymienilem sie kontaktami uzywajac programu do generowania foto kodu – zainstalowalem kilka przeroznych aplikacji i gier – zmienilem ustawienia swojego kontakt na playmobile – dodaje wpis do bloga postawionego na wordpresie

Nie liczac dwoch gluchaczy, ktore wyslalem dla proby nie wykonalem jak dotad zadnego telefonu.

Telefon w urzadzeniu z zainstalowanym androidem to jedynie jedna z wielu funkcji i jak dla mnie – przynajmniej narazie – nie najwazniejsza.

Kategorie:Bez kategorii Tagi:

Jak wydobyć rozszerzenie z nazwy pliku.

Kwiecień 6th, 2010 Zbigniew Heintze 2 comments

Jednym z ważniejszych zabiegów optymalizujących kod aplikacji jest używanie przy wykonywaniu poszczególnych operacji, funkcji do tego dedykowanych. Powszechną jest opinia o nadużywaniu np. wyrażeń regularnych, czy też pisaniu własnych funkcji, których odpowiedniki są już zaimplementowane w samym PHP.

Wydobycie rozszerzenia z nazwy pliku nie jest operacją zbyt skomplikowaną i zasobożerną jednak da się ją wykonać na kilka różnych sposobów. Postanowiłem przeprowadzić mały test sprawdzający, które z przyjętych rozwiązań wykona owo zadanie najsprawniej.

Na początek przedstawię kilka sposobów wyekstrahowania rozszerzenia z pełnej ścieżki do pliku.

Na początek użycie funkcji pathinfo

function get_ext_using_pathinfo($path) {
	$parts = pathinfo($path);
	return $parts['extension'];
}

Użycie funkcji pathinfo ze stałą PATHINFO_EXTENSION – dostępną od wersji PHP 5.2

function get_ext_using_pathinfo_with_const($path) {
	return pathinfo($path, PATHINFO_EXTENSION);
}

Użycie funkcji operujących na tekście substr i strrpos

function get_ext_using_substr_and_strrpos($path) {
	return substr($path, strrpos($path, ".") + 1);
}

Użycie wyrażeń regularnych a dokładnie funkcji preg_replace

function get_ext_using_preg_replace($path) {
	return preg_replace('/.*\.([a-zA-Z0-9]*)$/', '\\1', $path);
}

Użycie wyrażeń regularnych z tymże tym razem funkcji preg_match

function get_ext_using_preg_match($path) {
	preg_match('/.*\.([a-zA-Z0-9]*)$/', $path, $matches);
	return $matches[1];
}

Wykonanie exploda i wydobycie ostatniego elementu tablicy funkcją array_pop

function get_ext_using_explode($path) {
	return array_pop(explode('.', $path));
}

Przez każdą z wyżej wymienionych funkcji – w pętli for – 10 tys. razy przepuściłem zmienną zawierającą przykładową ścieżkę do pliku.

$path = '/home/user/workplace/project/images/file.sufix.ext';

Operację tę wykonałem kilkukrotnie zapisując wyniki do pliku. Po uśrednieniu i zaokrągleniu wyników wyszło mi:

substr i strrpos preg_replace preg_match pathinfo ze stałą PATHINFO_EXTENSION explode i array_pop pathinfo
0.077 0.0822 0.0904 0.0952 0.1049 0.1310

Jak wynika z powyższego zestawienia najlepiej spisały się funkcje operujące na stringach. Funkcje preg_replace i preg_match pozytywnie mnie zaskoczyły gdyż spodziewałem się, że zaprzęgnięcie do tak prostej pracy tak potężnej maszyny jaką są wyrażenia regularne będzie obarczone sporą stratą czasu. Z kolei bardzo zawiodłem się na wbudowanej funkcji pathinfo, którą dotąd najczęściej wykorzystywałem do wydobycia potrzebnych mi informacji ze ścieżki. Myślałem, że jest bardziej wydajna, a tu się okazało, że w wersji uniemożliwiającej użycie stałej PATHINFO_EXTENSION jest ona wolniejsza nawet od exploda. Nie skreślałbym tej funkcji w przypadku chęci uzyskania kompletu danych o ścieżce jednak dla atomowej operacji wydobycia rozszerzenia warto pomyśleć o innym sposobie. Z drugiej strony, różnice jak widać nie są znowu tak wielkie, więc dla tego prostego zadania w 99% przypadków użycia nie będzie miało znaczenia, którego z rozwiązań użyjemy i spokojnie możemy kierować się wygodą.

Kategorie:Optymalizacja, PHP Tagi:

Krusader w Ubuntu – jak podpiąć terminal?

Marzec 29th, 2010 Zbigniew Heintze Brak komentarzy

Krusader jest dydykowany KDE jednak jeśli ktoś lubi dwa panele to równie dobrze można go uruchomić pod GNOME. Konfiguracja nie różni się właściwie od tej pod KDE poza kilkoma drobiazgami. W GNOME domyślnym edytorem jest „gedit” a konsolą „gnome-terminal” w związku z czym w zakładce Ustawienia -> Konfiguracja Krusadera -> Ogólne na karcie Podstawowe operacje w polu Edytor zamiast

internal editor
warto wpisać

gnome
natomiast w polu Terminal zamiast
konsole --workdir %d
powinniśmy wpisać
gnome-terminal --working-directory=%d
.

Tyle że po zapisaniu i wybraniu F2 terminal się uruchomi, ale bynajmniej nie w bieżącej lokalizacji. W Krusaderze jest błąd, który po zapisaniu zmienia %d na %25d czyli dostajemy gnome-terminal –working-directory=%25d. Można ten problem obejść edytując ręcznie plik konfiguracyjny ~/.kde/share/config/krusaderrc. W sekcji [General] wpisujemy

Terminal=gnome-terminal --working-directory %d
Proszę zwrócić uwagę na brak znaku równości „=”.

Kategorie:GNOME Tagi:

Udana konferencja 4Developers 2010

Marzec 26th, 2010 Zbigniew Heintze Brak komentarzy

W tym roku miałem okazję uczestniczyć w konferencji 4Developers. Świetnie przygotowana impreza zarówno z punktu widzenia organizacyjnego, jak i merytorycznego sprawiła, iż te kilka godzin prelekcji uznaję za bardzo dobrze spędzony czas, który przyniósł mi nie tylko masę pozytywnych wrażeń, ale przede wszystkim ograniczył nieco moją zawodową indolencję.

Więcej na ten temat napisałem na stronie wynurzenie.com, gdzie wszystkich Was serdecznie zapraszam.

Kategorie:Wydarzenia Tagi:

Tworzenie obiektów w JavaScript

Marzec 21st, 2010 Zbigniew Heintze Brak komentarzy

W JavaSripcie istnieje bazowa klasa Object, która stanowi prototyp wszystkich pozostałych obiektów JavaScript. Można jej użyć bezpośrednio do utworzenia obiektu.

    obj = new Object();
    obj.x = 1;
    obj.y = 2;

lub alternatywnie

    obj = {};
    obj.x = 1;
    obj.y = 2;

Nawiasy klamrowe stanowią semantyczny skrót podobnie jak użycie nawiasów kwadratowych (arr = []) może zastąpić arr = new Array(). Tablica czyli Array jest jednym z wielu wbudowanych w JavaScript obiektów podobnie jak Window, Document itd.

Aby utworzyć niestandardowy obiekt należy najpierw zdefinować prototyp Klasy, której instancją dany obiekt będzie. Najprościej utworzyć prototyp metodą konstruktora.

var Foo = function() {
    this.x = 1;
    this.y = 2;
    this.sum = function() {
       return this.x + this.y;
    }
}

W konstruktorze definiujemy właściwości i metody. Nową instancję tworzy się z użyciem operatora new.

    obj = new Foo();
    alert(obj.x);
    alert(obj.sum());

Do właściwości lub metod można się odwołać za pośrednictwem utworzonego w ten sposób obiektu, ale można też pominąć operację przypisania do zmiennej i wywołać metodę w sposób niemożliwy np. w PHP.

	alert(new Foo().sum());

Wywołując obj = new Foo(); powołuje się do życia instancje prototypu Foo. Można następnie wywołać metodę obj.sum();. Metodę sum można też wywołać z pominięciem przypisania obiektu do zmiennej new Foo().someMethod(); Tak czy inaczej zawsze w trzeba w pierwszej kolejności utworzyć obiekt.

Definiowanie klas metodą prototypu jest łatwe i intuicyjne, nie mniej w przypadku powoływania wielu obiektów danego prototypu zalecany jest sposób definiowania metod z użyciem prototype (nie mylić z frameworkiem prototype).

var Foo = function() { 
    this.x = 1;
    this.y = 2;
};
 
Foo.prototype.sum = function() {
   return this.x + this.y;
}

Różnica polega na tym, że w pierwszym przypadku przy powoływaniu do życia nowej instancji za każdym razem metoda „sum” tworzona jest na nowo, a w drugim przypadku jest to cały czas jedna i ta sama metoda. Zyskuję się na zaoszczędzonej pamięci co przy bardzo rozbudowanych skryptach nabiera znaczenia.

Zdefiniowanie metody z pominięciem słowa „prototype”:

var Foo = function() { };
 
Foo.sum = function(x, y) {
    return x+ y;
}

… daje możliwość wywołania metody klasy bez tworzenia obiektu Foo.sum(2,4); – to taki jakby odpowiednik metod statycznych w PHP. Analogicznie do metod statycznych w PHP użycie „this” wewnątrz takiej funkcji mija się z celem, więc gdybyśmy przez przypadek zdefiniowali:

var Foo = function() { 
    this.x = 1;
    this.y = 2;
};
 
Foo.sum = function() {
   return this.x + this.y;
}

to wywołanie Foo.sum(); zwróci „NaN” a z kolei new Foo().sum(); zakończy się błędem „TypeError on line 1: (new Foo).sum is not a function”.

W JS można też utworzyć obiekt ad hock

var Foo = { x: 1, y: 2, sum: function () { return this.x + this.y; } } W tym wypadku Foo nie jest prototypem tylko instancją prototypu Object dlatego oczywistym jest wywołanie Foo.sum(); z pominięciem operatora new.

Kategorie:Java Script Tagi:

perfectionorvanity.com – powrót po latach

Marzec 19th, 2010 Zbigniew Heintze 3 comments

Mówiąc krótko Piotr Petrus znów nadaje. Jeden z nielicznych blogów o tematyce webdeveloperskiej, które z chęcią czytałem z uwagi na wartość merytoryczną i estetyczną ginął powoli gdzieś tam w mrokach zapomnienia i myślałem już, że jego autor nigdy nie wznowi swojej Twórczości zagoniony obowiązkami dnia codziennego, pędem za karierą, pieniędzmi … ;) . To żart oczywiście. Nie mniej bardzo się cieszę, że pojawiły się nowe wpisy na perfectionorvanity.com i wierzę, że stare wpisy zostaną przywrócone bo jak widzę, gdzieś się zadziały

Kategorie:Wydarzenia Tagi: