Bonjour, Mieux vaut tard que jamais... 2 correctifs de fonctions dans lySQLiteFields : Code pascal : Sélectionner tout - Visualiser dans une fenêtre à part 123456789function TlySQLiteTable.getSubsetFieldByIndex(aCol, aIndex: integer): TlyField; begin if (aCol<0) or (aCol>FColCount-1) or (aIndex<0) or (aIndex>SubsetCount-1) then Result:=nil // correction du 18/04/2024 // else Result:=TlyField(FFields[Subset[aIndex]]); else Result:=TlyField(FFields[Subset[aIndex]*FColCount+aCol]); // fin correction end; Code pascal : Sélectionner tout - Visualiser dans une fenêtre à part 1234567891011121314151617181920212223242526function TlySQLiteTable.Locate(aValue: string; aCol: integer): Boolean; var i, l, index: integer; begin // FSubsetIndex:=-1; // comme ça, Next place sur First ! // toute nouvelle recherche efface et reconstitue l'ensemble résultat SetLength(Subset, 0); if (aCol<0) or (aCol>FColCount-1) then Result:=False else begin for i:=0 to FRowCount-1 do begin index:=i*FColCount+aCol; if TlyField(FFields[index]).AsText=aValue then begin l:=Length(Subset); SetLength(Subset, l+1); // correction du 18/04/2024 // Subset[l]:=index; Subset[l]:=i; // fin correction end; end; Result := (Length(Subset) > 0); end; end;
function TlySQLiteTable.getSubsetFieldByIndex(aCol, aIndex: integer): TlyField; begin if (aCol<0) or (aCol>FColCount-1) or (aIndex<0) or (aIndex>SubsetCount-1) then Result:=nil // correction du 18/04/2024 // else Result:=TlyField(FFields[Subset[aIndex]]); else Result:=TlyField(FFields[Subset[aIndex]*FColCount+aCol]); // fin correction end;
function TlySQLiteTable.Locate(aValue: string; aCol: integer): Boolean; var i, l, index: integer; begin // FSubsetIndex:=-1; // comme ça, Next place sur First ! // toute nouvelle recherche efface et reconstitue l'ensemble résultat SetLength(Subset, 0); if (aCol<0) or (aCol>FColCount-1) then Result:=False else begin for i:=0 to FRowCount-1 do begin index:=i*FColCount+aCol; if TlyField(FFields[index]).AsText=aValue then begin l:=Length(Subset); SetLength(Subset, l+1); // correction du 18/04/2024 // Subset[l]:=index; Subset[l]:=i; // fin correction end; end; Result := (Length(Subset) > 0); end; end;
Cette interface de sérialisation est beaucoup plus récente (apparue avec la version 3.23, le 02/04/2018) que les fonctions que j'ai utilisées. Qui plus est, je ne suis pas sûr d'avoir pensé en les découvrant qu'on puisse les utiliser dans cette optique ! Il me semble qu'avec cette solution se poserait le problème de cohérence des données en cas de bug avant réécriture chiffrée, si j'ai bien compris la philosophie d'utilisation, avec risque de perte de données ajoutées ou modifiées pendant la session.
Bravo et merci de partager cet excellent article ! Il tombe à point nommé alors que je me penchais sur cette problématique. J'envisage 2 solutions : - la vôtre - l'utilisation des fonctions sqlite3_serialize et sqlite3_deserialize Sauf erreur de ma part, vous ne mentionnez pas les fonctions sqlite3_serialize et sqlite3_deserialize. La fonction sqlite3_serialize permet d'obtenir un pointeur vers une zone mémoire contenant la base de données. Il est donc possible de chiffrer cette zone vers un fichier sur le disque. La fonction sqlite3_deserialize permet de charger une base de données à partir d'une zone mémoire dont le contenu peut être le résultat du déchiffrement d'un fichier sur le disque. C'est une autre manière de faire et pour laquelle je n'ai pas suffisamment de recul (notamment par rapport à la taille de la base de données). Avez-vous envisagé cette dernière solution ? Et si oui, pourquoi ne pas l'avoir retenue ? Merci beaucoup
trop top ce tuto
Article intéressant, le chiffrement c'est bien ! Cependant, petite incohérence sur les termes employés : on dit chiffrer/chiffrement et non crypter/cryptage. D'un point de vue cryptographique, crypter n'a pas de sens : ça voudrait dire qu'on chiffre une donnée sans savoir comment ni avec quelle clé. Et sans pouvoir la déchiffrer du coup puisqu'on ne sait pas comment elle a été chiffré... Plus d'infos là : https://chiffrer.info/
C'est un reliquat de Delphi 5, en effet... Le tutoriel Implémentation d'un singleton fait un tour de la question plus actuel. Merci.
La variable [c]UneSeuleInstance[/c] devrait être une variable de classe. Mais c'est peut être que ce n'est pas supporté par les anciennes versions de Delphi.
Envoyé par SergioMaster Par contre je trouve que c'est la porte ouverte à de l'injection SQL. Merci, Serge. Ta remarque est très intéressante sur la faiblesse par rapport à l'injection SQL. Je ressors des vieux trucs du placard, et le format blog me plaisait pour avoir justement ces retours sur des bugs ou évolutions/suggestions. Pourquoi, au bout du compte, ne pas retravailler l'ensemble en fonction des remarques, et en faire une synthèse sous une forme un peu différente ? L'avenir le dira...
Salut, Envoyé par SergioMaster le billet un peu long, pourquoi ne pas en avoir fait un tutoriel ? Tout y est. Il a cependant été publié sur les différents portails concernés comme tutoriel pour une meilleure visibilité. Excellent tutoriel Merci encore
Bonjour, le billet un peu long, pourquoi ne pas en avoir fait un tutoriel ? Tout y est. Par contre je trouve que c'est la porte ouverte à de l'injection SQL. En tout cas on y retrouve presque tout ce qu'offre les fonctionnalités de Firedac (paramètres, macros) et ça c'est :cool: