14
HTTPS, HSTS et redirection chez OVH
Web
14 août 2018

Pour forcer l'usage de SSL pour l'accès à votre site, c'est-à-dire forcer l'accès via « https:// » plutôt que « http:// », il convient d'ajouter les lignes suivantes à votre fichier .htaccess. Le code ci-dessous supprime aussi au passage le « www. » qui peut se glisser après « http:// ».

RewriteEngine on
RewriteCond %{SERVER_PORT} 80 [OR]
RewriteCond %{HTTP_HOST}  ^www\.website\.com$ [NC]
RewriteRule ^(.*) https://website.com/$1 [QSA,L,R=301]

Le code a pour effet de réécrire toutes les adresses en ajoutant un « s » à « http:// » pour forcer l'usage de ce protocole. On sait que cela a comme inconvénient de permettre initialement la connexion en HTTP (non sécurisée) pour lire le fichier .htaccess et seulement ensuite rediriger vers la page en HTTPS. Lors de cette première connexion non sécurisée une interception, puis éventuellement redirection vers un site maquillé, est possible. C'est le cas à chaque fois que l'on se connecte au site sans « https:// » dans l'adresse. Pour cette raison, HSTS (HTTP Strict Transport Security) a été inventé. Cette option enregistre sur le navigateur client et pour une durée donnée la préférence d'accès en HTTPS à tel site et opère la réécriture directement au niveau du navigateur client. On a ainsi besoin de se connecter qu'une seule fois de manière non sécurisée pour lire le fichier .htaccess. Cela limite les risques. HSTS se définit comme suit, dans le fichier .htaccess.

Strict-Transport-Security: max-age=31536000; includeSubDomains; preload

On peut même inscrire son site sur une liste blanche que les navigateurs ont en mémoire à l'installation et éviter absolument toute connexion non sécurisée.

Le risque, c'est que si le site en question n'a pas de certificat SSL, le perd, ou redirige vers un autre site sans certificat, le navigateur revoie un erreur. Et l'on ne pourra plus se connecter en HTTP au site car le navigateur a enregistré qu'il fallait toujours se connecter en HTTPS. Changer votre .htaccess n'aura pas d'effet, car l'information est stockée localement sur le navigateur de vos visiteurs. Cela, jusqu'à l'expiration du max-age (en secondes) défini dans le .htaccess comme ci-dessus. Le HSTS est donc assez dangereux si on y prend pas garde, surtout si vous le configurez pour une durée longue. Pour info, vous pouvez effacer la mémoire de votre navigateur concernant les préférence HSTS de tel site. Sur Firefox, voir Historique > clic droit sur le site Oublier ce site.

Si vous avez configuré des redirections avec votre hébergement OVH, elles ne pourront pas se faire en HTTPS à ma connaissance. Elles pourront cependant bien mener en bout de chaîne à une page en HTTPS. Par exemple, http://page.domaine.co peut rediriger vers https://domaine.com/pages/page mais l'accès à https://page.domaine.com vous renverra une erreur de certificat. En effet, le serveur de redirection d'OVH par lequel on transit est différent du serveur prévu dans le certificat délivré pour votre site. Pour renvoyer vers une page en HTTPS, il faut opter pour une redirection visible. Ainsi, si vous utilisez les redirections OVH, il ne faut pas utiliser HSTS.

Attention, des applications (CMS ou autre) que vous avez installé sur votre site, peuvent contenir des directives HSTS dans le .htaccess de leur sous-dossier mais qui s'appliquent à l'ensemble du domaine. C'est le cas de Own/Next-cloud ou FileRun par exemple. Il faudra alors éditer le fichier .htaccess en question et mettre un "#" devant la ligne configurant le HSTS pour le désactiver.

13
Triangulation de Delaunay entre des points dans QGIS
Python, Qgis
13 mai 2018

Au travers de l'interface Python, on peut construire une triangulation de Delaunay entre des points QGIS. Ou plutôt : on ne peut pas directement – du moins pas à ma connaissance – mais on peut faire appel à librairie externe qui sait le faire.

Triangulation de Delaunay entre des points
Triangulation de Delaunay entre des points

C'est légèrement bricolé, mais efficace. J'utilise les fonctions du projet delaunay de Peter Beard. On a besoin ici uniquement du fichier geometry.py qui contient les routines géométriques nécessaires. Pour faire appel à ces fonctions dans pyQGIS, il faut placer le fichier dans le dossier lib de l'installation Python de QGIS. Sous Windows et si vous avez installé QGIS via OSGeo, ce sera ici C:\OSGeo4W64\apps\Python27\Lib.

Ci-dessous le code d'une utilisation typique

# coding: utf8

from qgis.core import *
from qgis.gui import *
from PyQt4.QtCore import *
from PyQt4.QtGui import *

import math
from geometry import *
# by Peter Beard, https://github.com/PeterBeard/delaunay
# to import Python external library to QGIS, put the .py (here geometry.py) file in C:\OSGeo4W64\apps\Python27\Lib

inputPts = [QgsPoint(7.7,48.6), QgsPoint(2.3,48.9), QgsPoint(4.3,50.8), QgsPoint(13.4,52.5), QgsPoint(12.6,55.7), QgsPoint(-0.1,51.5), QgsPoint(5.4,43.3)]
#Qgis Point objects (Strasbourg, Paris, Berlin, Copenhagen, London, Marseille)


# Translate Points (Qgis Point objects) into geometry.py points

delaunayPts = []
for pt in inputPts:
    geometryPoint = Point(pt.x(), pt.y())
    delaunayPts.append(geometryPoint)

delaunayTriangles = delaunay_triangulation(delaunayPts) #returns geometry.py Triangle objects


# Get lines from group of Delaunay triangles

delaunayLines = [] #Pairs (here tuples) of Qgis Point objects (start and end of line)

for triangle in delaunayTriangles:
    pointA = QgsPoint(triangle[0].x, triangle[0].y)
    pointB = QgsPoint(triangle[1].x, triangle[1].y)
    pointC = QgsPoint(triangle[2].x, triangle[2].y)

    if pointA in inputPts and pointB in inputPts:
    #excludes automatically created bounding points from geometry.py

        lineA = (pointA, pointB)
        delaunayLines.append(lineA)

    if pointA in inputPts and pointC in inputPts:
        lineB = (pointA, pointC)
        delaunayLines.append(lineB)

    if pointB in inputPts and pointC in inputPts:
        lineC = (pointB, pointC)
        delaunayLines.append(lineC)


# Delete duplicates

def removeTupleDuplicatesinArray(array):
    duplicateFreeArray = []

    for t in array:
        if (t[0],t[1]) not in duplicateFreeArray and (t[1],t[0]) not in duplicateFreeArray:
            duplicateFreeArray.append(t)
    return duplicateFreeArray

delaunayLines = removeTupleDuplicatesinArray(delaunayLines)


# Preview lines

for line in delaunayLines:
    rb = QgsRubberBand( qgis.utils.iface.mapCanvas(), True )
    rb.setColor (Qt.blue)
    rb.addPoint(QgsPoint(line[0].x(), line[0].y()))
    rb.addPoint(QgsPoint(line[1].x(), line[1].y()))
12
Exporter une image d'un canvas protégé depuis Firefox
Web
1er mai 2018

Certains sites d'archive offrent à leurs visiteurs des lecteurs d'image qui permettent la visualisation d'une partie de la photo en gros plan (et donc en haute résolution) mais empêchent le téléchargement de l'image entière à cette résolution. Comme en cartographie, elle est découpée en carreaux pour empêcher d'obtenir l'adresse de l'image haute définition par l'écoute du réseau. Ces carreaux sont cependant bien réassemblés par le lecteur pour permettre la navigation en gros plan. Pour télécharger l'image complète en haute définition, on peut donc exporter une « capture » du lecteur si celui-ci est un objet <canvas>.

Je vais prendre l'exemple d'une image sur le site des Bibliothèques spécialisées de Paris. Sur ce site, on nous laisse télécharger les images mais dans une résolution inférieure que celle du <canvas>.

Avec l'Inspecteur de la barre d'outils de développement (F12) de Firefox on cherche l'élément <canvas>. Puis Clic droit dessus et « Ouvrir dans la console ». La console s'ouvre avec le nom de l'objet renseigné, généralement temp0. On copie-colle dans la console les trois lignes suivantes en prenant soin de modifier temp0 si le nom de l'objet est différent.

var d = temp0.toDataURL();
var w = window.open('about:blank','image from canvas');
w.document.write("<img src='"+d+"' alt='from canvas'/>");

On exécute, l'image extraite s'affichera dans un nouvel onglet.

Une astuce supplémentaire pour obtenir la meilleure résolution possible consiste à forcer un <canvas> de grande taille en réduisant le niveau de zoom du navigateur (Ctrl -) avant d'executer le script. Idem pour obtenir la totalité de l'image est non uniquement un gros plan.

11
Ajouter des règles CSS (en CSS !) à une page via Javascript
Javascript, Web
11 avr 2018

Evite de devoir retraduire en instructions purement Javascript. Ajoute au DOM un élément <style>.

var cssRules = "body{background-color: rgba(150,200,200,1);} div{border: .5vw white solid;} p{text-size: 10vw; color: white;}";

var style = document.createElement("style");
style.type = "text/css";
style.appendChild(document.createTextNode(cssRules));

document.head.appendChild(style);

Attention au formatage des règles CSS (sauts de ligne, apostrophes, ...) si l'on reprend son code depuis un fichier CSS.

10
Rogner plusieurs images d'un coup avec ImageMagick
Windows
5 mar 2018

Pour automatiser le rognage d'une série d'images, par exemple pour enlever le filigrane (logo), on peut utiliser les exécutables de ImageMagick. Pour utiliser ImageMagick sur Windows, le plus simple est de télécharger la version portable du logiciel et de placer les fichiers téléchargés dans un dossier qui contient les images à traiter.

Dans l'invité de commande (~Terminal), on va ensuite chercher ce dossier pour faire appel aux fonctionnalités. Pour faire propre, je garde le dossier ImageMagick comme sous-dossier de mon répertoire de travail contentenant les images. Ici je l'ai renommé im, d'où la commande suivante.

im\convert *.jpg -crop 1920x1000+0+0 converted_%04d.jpg

Dans cet exemple, 1920 par 1000px sera la taille finale de toutes les images, avec le rognage démarré en haut à gauche.

9
Remplacer des courbes par un bloc de taille équivalente
Python, Rhino3D
25 mai 2017

Sert typiquement à remplacer des éléments (non-blocs) répétés à différentes tailles par un bloc de taille équivalente.

A l'origine je l'utilisais pour insérer un bloc d'arbre 3D à la place de chaque cercle de tronc du plan de géomètre, sachant que ces derniers sont de taille différentes. L'astuce pour obtenir exactement la même taille que le tronc en plan, est de fabriquer un bloc d'arbre 3D dont le tronc mesure exactement 1 m². Ainsi, on peut simplement mettre à l'échelle ce bloc par un facteur égal à la racine carrée de l'aire du tronc géomètre.

import rhinoscriptsyntax as rs
import math

curves = rs.GetObjects("Select closed curves ...")
blockName = rs.GetString("Name of block to copy ...")

if curves:
    for curve in curves:
        if rs.IsCurveClosed(curve):
            surface = rs.AddPlanarSrf(curve)
            area = rs.SurfaceArea(surface)[0] 
            scale = math.sqrt(area)
            point = rs.SurfaceAreaCentroid(surface)[0] 

            rs.DeleteObject(surface)
            rs.InsertBlock(blockName, point, [scale,scale,scale], 0)
        else:
            print "Not a curve or curve not closed."
8
Plaquer des objets sur une surface avec Rhino Python
Python, Rhino3D
1er mar 2017
PutOnSurface.py démo

Script permettant de faire « tomber » des objets sur une face, c'est à dire les placer automatiquement au point d'intersection avec la surface, comme s'ils étaient physiquement posés dessus. L'intersection se calcule verticalement (vecteur Z) mais on peut choisir d'utiliser le z d'un plan de construction. On a également la possibilité d'ajouter une marge supplémentaire (offset) à la chute pour masquer certaines parties de l'objet (racines d'un arbre par exemple).

import rhinoscriptsyntax as rs

objectIds = rs.GetObjects("Select objects")
projectionSrfId = rs.GetObject("Select surface or polysurface to project to", rs.filter.polysurface | rs.filter.surface)

planes = []
planes.append("WorldXY") # add World XY

cplanes = rs.NamedCPlanes() # add named CPlanes
if cplanes:
    for cplane in cplanes:
        planes.append(cplane)

projectionPlane = rs.GetString("Plane to use for direction of projection (World or named CPlanes)", "WorldXY", planes)
offset = rs.GetReal("z Offset", 0)

if projectionSrfId:
    if objectIds:
        for objectId in objectIds:
            box = rs.BoundingBox(objectId,rs.NamedCPlane(projectionPlane), True) #if CPlane name is not found, falls back on WorldXY

            if box:
                bottomRightPt = [0,0,0]
                topLeftPt = [0,0,0]
                bottomLeftPt = [0,0,0]
                for i, point in enumerate(box):
                    if i==1:
                        bottomRightPt = point
                    if i==7:
                        topLeftPt = point
                    if i==3:
                        bottomLeftPt = point
                diagonal = rs.AddLine(topLeftPt, bottomRightPt)
                centroidPt = rs.CurveMidPoint(diagonal)
                rs.DeleteObject(diagonal)

                zVector = rs.VectorCreate(bottomLeftPt, topLeftPt)
                zVector = rs.VectorDivide(zVector, 2)
                zVectorU = rs.VectorUnitize(zVector)
                offsetVector = rs.VectorScale(zVectorU,-offset)

                bottomCentroidPt = [centroidPt[0] + zVector[0], centroidPt[1] + zVector[1], centroidPt[2] + zVector[2]]

                projectedPts = rs.ProjectPointToSurface(bottomCentroidPt, projectionSrfId, zVector)

                if projectedPts:
                    nearestProjectedPtId = rs.PointArrayClosestPoint(projectedPts, bottomCentroidPt)
                    destinationPt = projectedPts[nearestProjectedPtId]
                    rs.AddPoint(destinationPt)

                    projectVector = rs.VectorCreate(destinationPt,bottomCentroidPt)
                    if offset != 0:
                        projectVector = rs.VectorAdd(projectVector,offsetVector)
                    rs.MoveObject(objectId, projectVector)
                else:
                    print "Object cannot be projected on surface."
            else:
                print "Bounding-boxes couldn't be created."

    else:
        print "No object selected."
else:
    print "No surface selected."
7
Nettoyer le Rubberband de PyQGIS
Qgis, Python
18 jan 2016

Avec PyQGIS on fait souvent appel à l'élément RubberBand en phase de test pour afficher un aperçu de ce que l'on calcule. Le problème c'est qu'il reste affiché d'une exécution du code à l'autre. C'est alors pratique d'une cette fonction, à lancer en début de script, pour nettoyer ces « élastiques » avant chaque nouveau lancement.

def removeRubberbands():
    rbb_items = [ i for i in iface.mapCanvas().scene().items() if issubclass(type(i), qgis.gui.QgsRubberBand)]

    for rbb in rbb_items:
        if rbb in iface.mapCanvas().scene().items():
            iface.mapCanvas().scene().removeItem(rbb)
6
Filtrer les clés d'une archive OSM
Qgis, Osm
16 sept 2016

Dans cette note j'expliquais comme on peut réduire à une zone un fichier OSM. De même il est souvent utile de réduire ce fichier aux clés qui nous intéressent uniquement. Pour ce faire, on a le programme osmfilter.

C'est un exécutable qui s'utilise de la même manière que osmconvert, via l'invité de commande en plaçant le programme et le fichier OSM dans le même dossier.

Pour sélectionner les clés OSM, vous pouvez consultez la liste des contenus OpenStreetMaps avec leur nom. Dans mon cas je veux extraire uniquement les villages et hameaux, soit les entrées place:village et place:hamlet. La commande pour mon fichier OSM pour le Luberon sera :

osmfilter luberon.osm --keep="place=village place=hamlet" -o=luberon_village_hamlet.osm

On peut utiliser un astérisque pour pour prendre toute les valeurs d'une clé. Pour toutes les place par exemple on écrira -keep="place=*".

Une fonction autre utile de ce programme permet de lister les clés présentes sur un fichier avec leur quantité. On utilisera la commande suivante :

osmfilter luberon.osm --out-count

On peut également regarder à l'intérieur d'une clé, ici place

osmfilter luberon.osm --out-count=place

Pour ceux qui utilisent l'invité de commande natif de Windows, vous serez peut-être embettez par les très longues listes de clés si vous appliquez la fonction à un fichier OSM complet. La barre de défilement va être bloquée à un certain niveau. Pour visualiser la totalité de la liste, vous devrez utiliser un autre invité de commande, comme ComEmu.

5
Importer des données OSM dans QGIS
Osm, Qgis
9 sept 2016

QGIS s'utilise très bien avec OpenStreetMaps mais pour importer ses données OSM dans QGIS, ce n'est pas aussi direct qu'on pourrait le penser.

La première étape consiste à se procurer des données OSM brutes, via les extraits Geofabrik. L'extension qui nous intéresse est .osm.pbf. Choissez la zone la plus réduite possible selon vos besoins. Les fichiers sont lourds et on a tout à gagner à travailler avec des zones resserrées. Pour affiner son fichier, on peut encore réduire à un cadre géographique précis ou filtrer les clés qui nous intéressent.

En utilisant osmconvert on convertit l'archive OSM .osm.pbf en .osm (décompressé) via la commande suivante :

osmconvert alsace-latest.osm.pbf -o=alsace-latest.osm

Pour importer ce fichier dans QGIS, on va dans Vecteur > OpenStreetMaps > Importer la topologie depuis un XML. Sélectionnez votre fichier .osm et faites OK, puis Fermer. Cette opération créera une base de donnée lisible par QGIS de votre fichier sous l'extension .osm.db.

Pour afficher cette base de donnée sur votre carte, cherchez Vecteur > OpenStreetMaps > Exporter la topologie OSM vers Spatialite. Sélectionnez le fichier .osm.db, cliquez sur Charger depuis une base pour afficher les étiquettes disponibles. Faites votre choix, séléctionnez un type d'export et cliquez sur OK.

Si vous avez des difficultés avec la projection, sachez qu'OpenStreetMaps utilise Pseudo-Mercator, code EPSG:3857.