Bevezetés a LINQ-be

RoliSoft
2010 February 10, Wednesday 13:25

Ahhoz, hogy egy adatforrásból adatot nyerjünk ki, az adatforrás saját API-ját kell használnunk. Például egy SQL szervernek az ADO.NET segítségével küldünk egy SQL queryt, és így kapjuk meg a kívánt adatot; XML-ből viszont XPath vagy valamilyen XML DOM API segítségével nyerhetünk ki adatot. Mivel minden adatforrás használatához más API szükséges, ezért ezek megtanulása sok időt és energiát igényel. A LINQ ennek a megoldására lett létrehozva.

A LINQ-t három kategóriába lehet osztani:

  1. LINQ: Language Integrated Query for in memory objects
  2. DINQ: Language Integrated Query for databases
  3. XLINQ: Language Integrated Query for XML

A Microsoft úgy tervezte a LINQ-t, hogy minden olyan adattal tudjon dolgozni, ami implementálta az IEnumerable interfészt.

LINQ 1

A következő példában egy string tömbből válasszuk ki a 4 karakter hosszú stringeket:

string[] gyumolcsok = { "alma", "körte", "eper", "kivi", "barack" };

IEnumerable<string> query = from n in gyumolcsok
                            where n.Length == 4
                            select n;

foreach (string gyumolcs in query) Console.WriteLine(gyumolcs);

LINQ használata objektumokon

Bármikor, amikor tömbökkel vagy listákkal dolgozol használhatsz LINQ kifejezéseket. Az unalmas foreach ciklusokat az if-ekkel bennük, le tudod cserélni egy szépen olvasható LINQ kifejezésre, így szebb, olvashatóbb és rövidebb kódod lesz.

Tegyük fel, hogy meg szeretnéd keresni az összes svchost.exe futó alkalmazást, majd memóriahasználatuk szerint sorrendbe rendezni. Ezt eddig így csináltad meg .Net 2.0-ban:

List<Process> svchostLista = new List<Process>();

foreach (Process p in Process.GetProcesses())
{
	if(p.ProcessName == "svchost")
	{
		svchostLista.Add(p);
	}
}

svchostLista.Sort(delegate(Process p1, Process p2)
{
	return p2.WorkingSet64.CompareTo(p1.WorkingSet64);
});

Le lehet egyszerűsíteni lambda kifejezésekkel:

List<Process> svchostLista = new List<Process>(
	Process.GetProcesses().ToList().FindAll(p => String.Equals(p.ProcessName, "svchost"))
);
svchostLista.Sort((p1, p2) => p2.WorkingSet64.CompareTo(p1.WorkingSet64));

Habár a munkát elvégzi, az utánad következő fejlesztőnek kicsit fejfájás lesz e kódot módosítani. Most viszont itt van ugyan ez, LINQ kifejezésekkel:

IEnumerable<Process> svchostLista = from p in Process.GetProcesses()
                                    where p.ProcessName == "svchost"
                                    orderby p.WorkingSet64 descending
                                    select p;

Könnyen érthető és módosítható.

LINQ használata XML fájlokon

Sok XML API létezik, a LINQ viszont különleges, mivel nem csak XML-t ismer, de az XML-en belül használhatsz XML DOM vagy XPath-et is.
A legelső string tömbös példa XML megfelelője:

XElement gyumolcsok = XElement.Parse(
	@"<gyumolcsok>
		   <gyumolcs>alma</gyumolcs>
		   <gyumolcs>körte</gyumolcs>
		   <gyumolcs>eper</gyumolcs>
		   <gyumolcs>kivi</gyumolcs>
		   <gyumolcs>barack</gyumolcs>
	 </gyumolcsok›"
);

IEnumerable<string> query = from n in gyumolcsok.Elements("gyumolcs")
                            where n.Value.Length == 4
                            select n.Value;

foreach (string gyumolcs in query) Console.WriteLine(gyumolcs);

Ha csak annyit szeretnénk megtudni, hogy az XML fájlban tárolt gyümölcsök közül hány kezdődik k betűvel, akkor a következő kód:

int hanyKBetu = (from i in gyumolcsok.Elements("gyumolcs") where i.Value.StartsWith("k") select i).Count();

Ebben az esetben a következő megoldás viszont rövidebb:

int hanyKBetu = gyumolcsok.Elements("gyumolcs").Where(i => i.Value.StartsWith("k")).Count();

A .Net 3.5-ben be lett vezetve az XElement, amely megengedi az XML fájlok funkcionális készítését:

XElement gyumolcsok =
	new XElement("gyumolcsok",
		new XElement("gyumolcs", "alma"),
		new XElement("gyumolcs", "körte"),
		new XElement("gyumolcs", "eper"),
		new XElement("gyumolcs", "kivi"),
		new XElement("gyumolcs", "barack")
);

Ha a gyumolcsok-re meghívjuk a ToString() függvényt, akkor megkapjuk a fentebb is látható XML fájlt.

LINQ használata SQL adatbázisokon

Ahhoz, hogy LINQ kifejezéseket használhassunk SQL adatbázisokon az első lépés az, hogy elkészítjük a táblánknak megfelelő osztályt.
A Northwind adatbázis Customer táblájának megfelelő osztály így néz ki:

[Table(Name = "dbo.Customers")]
public partial class Customer 
{              
    [Column(IsPrimaryKey = true)]
    public string CustomerID
    {
        get
        {
            return this._CustomerID;
        }
        set
        {
            if ((this._CustomerID != value))
            {
                this._CustomerID = value;
            }
        }                    
    }
    private string _CustomerID;

    [Column]
    public string CompanyName
    {
        get
        {
            return this._CompanyName;
        }
        set
        {
            if ((this._CompanyName != value))
            {
                this._CompanyName = value;
            }
        }
    }

    // és így tovább...
}

Két megoldás van arra, hogy egy osztályt egy táblához kössünk. Az egyik a fenti kód, ahol külön megírjuk a Table és Column részeket, míg a második megoldás a külső XML fájlok használata. Mindkét megoldáshoz vannak automatikus generátorok, mint például az sqlmetal.exe.

A DataContext osztály lefordítja a LINQ kifejezéseket SQL kifejezésekre, majd lefuttatja az adatbázison.
Ha a Northwind adatbázisból le szeretnénk tölteni a francia ügyfeleket, akkor a következő LINQ kifejezést futtatjuk le:

IEnumerable<Customer> ugyfelek = from c in context.Customers
                                 where c.Country == "France"
                                 orderby c.CustomerID ascending
                                 select c;

Ez le lesz fordítva a következő SQL kifejezéssé:

SELECT [t0].[CustomerID], [t0].[CompanyName], [t0].[ContactName], [t0].[ContactTitle], [t0].[Address],
[t0].[City], [t0].[Region], [t0].[PostalCode], [t0].[Country], [t0].[Phone], [t0].[Fax]
FROM [dbo].[Customers] AS [t0]
WHERE [t0].[Country] = @p0
ORDER BY [t0].[CustomerID]

A LINQ to SQL nagyon komplex kifejezéseket is képes megérteni és lefordítani, például amelyek két táblát join-olnak. Vannak esetek, ahol már túl komplex lesz egy query, és a LINQ to SQL már nem lesz képes megérteni; ilyenkor az Entity Framework-öt kell használni.

.htaccess trükkök

RoliSoft
2010 February 04, Thursday 17:23

Az Apache .htaccess fájlja nagyon hasznos lehet ha használni tudod, ugyanis sok esetben olyasmiket tud elvégezni amikre külön írnál egy scriptet. Amit meg lehet oldani .htaccess-ben azt ajánlott az alatt megcsinálni, ugyanis egy külön script csak feleslegesen terhelné a szervert.

  • Két domain egyesítése (rolisoft.net és www.rolisoft.net)
    RewriteEngine On
    RewriteCond %{HTTP_HOST} ^www\.rolisoft\.net [NC]
    RewriteRule ^(.*)$ http://rolisoft.net/$1 [R=301]
  • IP ban
    <Limit GET POST HEAD>
    	Order Deny,Allow
    	Deny from 123.123.123.123
    	Deny from 234.234.234.234
    	Allow from all
    </Limit>
  • Hotlinking megakadályozása
    RewriteEngine On
    RewriteCond %{HTTP_REFERER} !^$
    RewriteCond %{HTTP_REFERER} !^http://(www.)?oldalad_cime.hu/ [nc]
    RewriteRule .* http://oldalad_cime.hu/kepek/ne_lopj.jpg [nc]
  • PHP kiterjesztés eltávolítása
    RewriteEngine On
    RewriteRule ^(([^/]+/)*[^.]+)$ /$1.php [L]
  • Fájllistázás ki- és bekapcsolása
    Options +Indexes # + bekapcsolva; - kikapcsolva
    # egyes fájlok elrejtése a listázásból:
    IndexIgnore *.txt *.mp3 *.avi
  • Alapértelmezett fájl megváltoztatása
    DirectoryIndex kezdolap.html
  • Egyedi HTTP hibaüzenetek
    ErrorDocument 403 /tiltott.html
    ErrorDocument 404 /nem_talalhato.html
    ErrorDocument 500 /szerver_hiba.html
  • SSI engedélyezése – egyszerűbb műveletekre gyorsabb mint egy PHP script
    AddType text/html .shtml
    AddHandler server-parsed .shtml
  • Átirányítás
    # csak egy oldal átirányítása:
    Redirect regi_oldal.html http://www.ujcim.hu/uj_oldal.html
    # teljes honlap átirányítása az új címre:
    Redirect 301 / http://www.ujcim.hu/
  • Bizonyos oldalakról érkező felhasználók kitiltása
    RewriteEngine on
    RewriteCond %{HTTP_REFERER} tiltott_oldal\.hu [NC]
    RewriteCond %{HTTP_REFERER} masodik_tiltott_oldal\.hu [NC]
    RewriteRule .* - [F]
  • Bizonyos user agentek kitiltása – teljes kitiltható bot lista
    SetEnvIfNoCase user-Agent ^FrontPage [NC,OR]
    SetEnvIfNoCase user-Agent ^Java.* [NC,OR]
    SetEnvIfNoCase user-Agent ^Microsoft.URL [NC,OR]
    SetEnvIfNoCase user-Agent ^MSFrontPage [NC,OR]
    SetEnvIfNoCase user-Agent ^Offline.Explorer [NC,OR]
    SetEnvIfNoCase user-Agent ^[Ww]eb[Bb]andit [NC,OR]
    SetEnvIfNoCase user-Agent ^Zeus [NC]
    
    <Limit GET POST HEAD>
    	Order Allow,Deny
    	Allow from all
    	Deny from env=bad_bot
    </Limit>
  • Fájl kiszolgálásának megakadályozása
    <Files adatbazis.db3>
    Order allow,deny
    Deny from all
    </Files>
  • Script fájlok kiterjesztésének megváltoztatása
    # saját .rs kiterjesztés a PHP scripteknek:
    AddType application/x-httpd-php .rs
    # saját .rsi kiterjesztés a CGI scripteknek:
    AddType application/x-httpd-cgi .rsi
  • Fájltípusok letöltésének erőltetése
    AddType application/octet-stream .pdf
    AddType application/octet-stream .zip
    AddType application/octet-stream .mov
  • Tömörítés az Apache mod_deflate moduljával
    <IfModule mod_deflate.c>
    	<FilesMatch ".(js|css)$">
    		SetOutputFilter DEFLATE
    	</FilesMatch>
    </IfModule>
  • Fájl lejáratának elküldése
    <FilesMatch ".(ico|pdf|flv|jpg|jpeg|png|gif|swf)$">
    	Header set Expires "Wed, 20 May 2020 20:00:00 GMT"
    </FilesMatch>
  • Erőltetett caching
    FileETag MTime Size
    ExpiresActive on
    ExpiresDefault "access plus 86400 seconds"
  • Fájlok tömörítése a gzip modul engedélyezésével
    AddOutputFilterByType DEFLATE text/html text/plain text/xml application/xml application/xhtml+xml
    AddOutputFilterByType DEFLATE text/javascript text/css application/x-javascript
    BrowserMatch ^Mozilla/4 gzip-only-text/html
    BrowserMatch ^Mozilla/4.0[678] no-gzip
    BrowserMatch bMSIE !no-gzip !gzip-only-text/html

Ha még tudsz más trükköt is, akkor írd meg egy hozzászólásban!

Tippek PHP kód optimizálásához

RoliSoft
2010 February 01, Monday 14:58

Haladó programozók már figyelnek arra is, hogy a kódjuk milyen hamar fut le és mennyi erőforrást vesz igénybe. Látogatott oldalak esetében fontos, hogy a kód hamar lefusson és kevés erőforrást használjon, így több látogatót tudjon kiszolgálni. Az itt felsorolt tippek egyszerűen betarthatóak és hosszú kód esetén már elég sokat le tudnak faragni a futásidőből:

  • Ha egy osztály lehet statikus is, akkor használd deklaráld mint static class; körülbelül négyszer lesz gyorsabb.
  • Az echo sokkal gyorsabb mint a print.
  • Csökkentheted a memóriahasználatot, azzal, hogy több paramétert adsz meg az echo-nak, ahelyett hogy összeragaszd a stringeket:
    echo '<title>', $oldal['cim'], '</title>';
  • Használd az unset() függvényt, hogy szabadíts fel memóriát. Főleg ha hosszú stringekkel vagy nagy tömbökkel dolgoztál, és már nincs rájuk szükséged.
  • Tartsd magad távol a __get(), __set(), __autoload() meg hasonló megoldásoktól.
  • A require_once() sok erőforrást igényel. Ne használd.
  • Ahol csak lehet használj teljes útvonalakat a fájlokhoz, így nem kell felesleges időt eltöltenie a fordítónak rendszerhívásokkal, hogy megtalálja a teljes útvonalat.
  • Ha meg szeretnéd tudni a kódod mikor kezdte a futását akkor használd a $_SERVER['REQUEST_TIME'] változót, ahelyett hogy újat hozz létre a kódod elején.
  • A reguláris kifejezésekkel sok mindent meg lehet oldani, viszont nagyon lassúak. Próbáld meg először megoldani a problémád a strncasecmp(), strpbrk() vagy stripos() függvényekkel.
  • A str_replace() sokkal gyorsabb mint a preg_replace(), a strtr() viszont négyszer gyorsabb a str_replace() függvénynél.
  • Ha egy függvény, mint például a str_replace(), elfogad tömböt és stringet is paraméterként, a te listád viszont nem nagy és nem változó, akkor inkább többször hívd meg a függvényt, minthogy egy tömböt adj át neki.
  • Jobb ha switch-et használsz sok if/else helyett.
  • A hibaüzenetek elhallgattatására használt @ nagyon lassú.
  • A hibaüzenetek sok erőforrást igényelnek; óvakodj tőlük.
  • Kapcsold be az Apache mod_deflate modulját. Akár 80%-al is összetömörítheti az oldalad, így kevesebb lesz az adatforgalmad.
  • Zárd be az adatbázisaid kapcsolatait miután már nem használod őket vagy a kód végén.
  • Ne használj függvényeket a for() ciklusaidban!
    for($i = 0; $i <= count($tomb); $i++) // A count() meg lesz hívva minden egyes ciklusban!
  • Az $adatok['ar'] hétszer gyorsabb, mint az $adatok[ar].
  • A globális változók kétszer gyorsabbak, mint a helyi változók.
  • A leggyorsabb a helyi változó növelése. Majdnem olyan, mint egy helyi változóval dolgozni egy függvényben.
  • Egy objektum változójának növelése a leglassúbb. Például a $this->valtozo++; háromszor lassúbb mint egy helyi változó növelése.
  • Egy nem deklarált változó növelése tízszer lassúbb, mint egy deklarálté.
  • A jelenlegi osztályban található függvények hamarabb lefutnak, mint a szülő osztályban található függvények.
  • Egy üres függvény egy paraméterrel körülbelül annyi futásidőt használ, mint nyolcszor egy helyi változó növelése.
  • Ha a stringjeid ' közé rakod " helyett, akkor sokkal gyorsabban fognak lefutni, mivel a "-ben a PHP keres változókat is, míg '-ban nem.
  • Egy PHP fájl 2-10x lassabban lesz kiszolgálva az Apache által, és több erőforrást is igényel, mivel lefut a PHP compiler is. Ha a fájl nem tartalmaz PHP kódot, akkor statikus fájlként tárold.
  • A PHP kódjaid minden egyes futásnál le lesznek fordítva és csak utána futtatva. Sok időt és erőforrást takaríthatsz meg, ha telepítsz egy olyan modult amely cache-elni a lefordított kódot, így nem kell minden futásnál újrafordítani. Ilyen például az APC.
  • Cache-elj minél többet. Ahelyett, hogy minden egyes kis adatért kérést küldj az adatbázisodnak (pl MySQL), használj inkább memached-et.
  • Mikor biztos kell légy benne, hogy egy stringnek megvan egy bizonyos hosszúsága, akkor normális esetben meghívod rá a strlen() függvényt. Habár a strlen() egyáltalán nem egy terhelő függvény, mégis egy függvény, és lassú a meghívása a következő trükkhöz képest:
    if(!isset($nev{5})) die('A név rövidebb öt karakternél.');
    Az isset() nem egy függvény, hanem egy nyelvi konstrukció, így sokkal gyorsabb a meghívása.
  • Ha egy változó értékét növeled vagy csökkented, az $i++ lassúbb mint, a ++$i. Ez az érdekesség csak a PHP nyelvben van jelen. Az $i++ meghívásakor a fordító készít egy átmeneti másolatot, megnöveli, majd ezt visszamásolja az eredeti változóba; a ++$i viszont már egyből a kért változó értékét növeli.
  • Nem kell mindent OOP-ban megírj. Sok memóriát használ.
  • Nem kell mindenféle adatnak saját osztályt írj, majd ebben tárold; így nagyon sok memóriát pazarolsz el. Ilyen célra vannak a tömbök.
  • Ha olyan függvényekkel dolgozol, amelyek nagyon sok erőforrást és időt használnak, próbáld meg őket átírni C nyelvre és töltsd be mint PHP kiterjesztést.
  • Használj egy code profilert, mert ezek megmutatják a kódod melyik része a lassú. Ilyen például az xDebug.

Ha még tudsz más trükköt is, akkor írd meg egy hozzászólásban!

Egyszerű fájltitkosítás OpenSSL-el

RoliSoft
2009 August 29, Saturday 18:32

Linuxra (vagy bármelyik más operációs rendszerre) sokféle fájltitkosító szoftver létezik. De mi van akkor ha gyorsan kell fájlt titkosítani?

Az OpenSSL a legtöbb Linux disztribúcióra (pl. Ubuntu) már előre telepítve van. A Windows felhasználók innen tölthetnek le egy win32 binárist.

A legegyszerűbb parancs egy fájl titkosítására:

openssl aes-256-cbc -salt -in titkosFajl.txt -out titkositottFajl.aes

A fenti parancs a következőképpen működik:

  • openssl – az OpenSSL szoftver
  • aes-256-cbc – titkosítási algoritmus, ez esetben egy 256 bites AES CBC módban; a Wikipédia szerint a U.S. kormány ezt az algoritmust használja információk titkosítására.
  • salt – növeli a jelszó biztonságát, használata erősen ajánlott.
  • in titkosFajl.txt – titkosítani kívánt fájl neve.
  • out titkositottFajl.aes – ebbe a fájlba menti el a titkosítást.

Opcionálisan hozzá lehet adni az -a paramétert és akkor a kimenet Base64 kódolt lesz, így megtekinthető lesz bármilyen szövegszerkesztővel, habár nem lesz sok értelme, továbbá a fájl méretét is erősen növeli.

A dekódolás hasonlóképpen történik:

openssl aes-256-cbc -d -in titkositottFajl.aes -out titkosFajl.txt

Ha használtad titkosításkor az -a paramétert, akkor azt most is hozzá kell adni.

Másik módszer a GnuGP használata. Valószínűleg már ez is előre telepítve van a rendszereden, a Windows felhasználók pedig innen tölthetnek le egy win32 binárist.

GPG-vel a fájltitkosítás a következőképpen működik:

gpg --cipher-algo AES256 -o titkositottFajl.gpg -c titkosFajl.txt

A GPG alapból CAST5 algoritmust használ, de ajánlott ezt felülírni AES256-ra. Kimenetet (-o) nem kötelező megadni, ekkor a fájlnévhez hozzácsatol egy .gpg kiterjesztést.

A dekódolás a következőképpen történik:

gpg -o titkosFajl.txt -d titkositottFajl.gpg

A használt algoritmust automatikusan felismeri, így azt nem kell neki megadni. Itt is el lehet hagyni a kimenetet, ekkor kiírja a szöveget a konzolba.

Ha sokszor használsz fájltitkosítást akkor leegyszerűsítheted a folyamatot két bash script írásával. Az első script titkosításra van, tárold el például egy encrypt nevű fájlba:

#!/bin/bash
openssl aes-256-cbc -salt -in $1 -out $1.aes

Használata egyszerűen encrypt fajl.txt, beírod a jelszót, majd a fajl.txt.aes fájlban találod meg a titkosított tartalmat.
A dekódoló script is ilyen egyszerű. Tárold a következőket egy decrypt nevű fájlba:

#!/bin/bash
openssl aes-256-cbc -d -in $1 -out ${1%.aes}

Használata egyszerűen decrypt fajl.txt.aes, beírod a jelszót, majd a dekódolt tartalmat a fajl.txt-ben találod meg.

C# és Java közötti hasonlóság példa kódokkal

RoliSoft
2009 August 21, Friday 03:45

Program struktúra

C#

using System;

namespace Hello {
    public class HelloWorld {
        public static void Main(string[] args) {
            string nyelv = "C#";
            
            // megnézzük, hogy kaptunk-e valamit a parancssorból
            if (args.Length == 1)
                nyelv = args[0];
            
            Console.WriteLine("Helló " + nyelv + "!");
        }
    }
}

Java

package hello;

public class HelloWorld {
    public static void main(String[] args) {
        String nyelv = "Java";
        
        // megnézzük, hogy kaptunk-e valamit a parancssorból
        if (args.length == 1)
            nyelv = args[0];
        
        System.out.println("Helló " + nyelv + "!");
    }
}

Bővebben... »