Skip navigation.

exploreopera

| Help

Sign up | Help

SPIP commits

[Howto] Control of the uploaded picture size

,

You can limit the size of the uploaded pictures with the constants (in mes_options.php) :
define('_IMG_MAX_SIZE', 0); # size in Kb
define('_IMG_MAX_WIDTH', 0); # width in pixels 
define('_IMG_MAX_HEIGHT', 0); # height in pixels

For documents it's :
define('_DOC_MAX_SIZE', 0); # size in Kb

If the limitations are not respected, the upload is aborted and an error message is displayed

[11922] Customize the keyword box in the private area

, , ,

With this commit, some keyword groups can be displayed/hidden in specific sections.
The customization can be done with autoriser_xxx_editermots($action,$what,$id,$who,$opts.
$opts contains the id of the concerned keyword group, and also the fields of this group that can be displayed.
By default, the function only checks if the author is authorized to this group.

No, I don't like like SPIP (or try to hide it ;)

@define('_SPIP_SCRIPT', 'joomla.php');
@define('_DIR_RESTREINT_ABS', 'private/');
@define('_HEADER_COMPOSED_BY', "Composed-By: JOOMLA");
$GLOBALS['spip_header_silencieux'] = 1;

=> http://tech-nova.fr/lacigale/joomla.php?rubrique37

shame on me ! :D

How does the login form really works ?

The login process seems to be quite mysterious, but thanks to the developper toolbar and Firebug you can see it completly naked :-)

The screencast is here : http://screencast.com/t/eiiGjNt7

So it works like this :
- The action is the same url (and the form can display errors).
- The form initially contains several hidden values that will make the submit action more secure.
- When the focus is set to the password field, the form verifies that the encryption parameters are OK, and indicates it with a brown padlock.
- Before been submitted, the password is encrypted into two md5+salt values, and the non-encrypted password field is erased : Therefore the password is never directly sent to the server, so it can't be catched by a bad guy. That makes the login form really secure !
- Finally, the server calculates the md5+salt values of the password in database. It compares these values to the encrypted received values. If the values match, the password that has been submitted is correct. Elsewhere it's bad and SPIP returns to the login form with an error.



Enjoy !

The parameter "var_mode" detailled

, ,

4 values can be used :

  • ?var_mode=preview : enables to display an article without publishing it.
  • ?var_mode=calcul : refreshes the cache
  • ?var_mode=recalcul : regenerates the templates and refreshes the cache
  • ?var_mode=debug : shows informations relating to the page calculation


Generally you must be authenticated to use these parameters. The debug mode is accessible to admins only.

Plugins : My list

Nagigate throught this concept map :









A full screen version of the interactive map is available here :
http://tech-nova.fr/blog/carte-flash-plugins.html

You can download a screenshot here :
(jpeg, 1.8Mb)


[11355] Overwrite a criteria for a specific loop only

, ,

For exemple, the function critere_AUTEURS_recherche_dist() overwrites the criteria recherche for the loop AUTEURS only. The priority order is :
  1. critere_TABLE_nomcrit()
  2. critere_TABLE_nomcrit_dist()
  3. critere_nomcrit()
  4. critere_nomcrit_dist()

[11440] SQL views in the API

, , ,

3 new functions enable to create and delete views for PG, SQlite and MySQL :

  • sql_get_select() : same arguments as sql_select() but returns the query without evaluating it
  • sql_create_view($view_name, $select_request) : creates the view $view_name for the select request $select_request.
  • sql_drop_view($view_name) : drops the view.


/!\ Warning ! Yous must give an explicit name to every field prefixed with a table name or an alias. Elsewhere SQLite won't be able to read the view (which contains 'a.titre' instead of 'titre').

Example :
$sel = sql_get_select(
          array(
            'id_article'=>'id_article', 
            'titre'=>'titre'
          ),
          'spip_articles'); 
echo "requete select : $sel<br />"; 
sql_create_view('vue_nom', $sel);

$res = sql_select(array('id_article', 'titre'),'vue_nom',,,,'10');
if ($res){
   while ($r = sql_fetch($res)){
      echo "*" . $r['id_article'] . " - " . $r['titre'] . "<br />";
   }
}

sql_drop_view('vue_nom');

[11435] MySQL views can be used in SPIP loops

, , ,

SQL views are known to be used like tables.
They enable to :
- mask the schema complexity ( -> simplification of queries)
- give access to a limited number of fields ( -> security)
- manipulate calculated fields (sum(), max(), avg(), ..)

Now you can avoid writing complexe loops by using views :

Example :
mysql> create view v AS 
         SELECT a.titre,a.id_article,b.id_rubrique,b.titre AS titre_rub 
         FROM spip_articles AS a 
         LEFT JOIN spip_rubriques AS b ON(a.id_rubrique=b.id_rubrique)
         WHERE b.titre REGEXP '^A'
         ORDER BY a.titre DESC;


template :
<BOUCLE_n(V)>
 <div>#TITRE : #TITRE_RUB</div>
</BOUCLE_n>


SPIP implements this for MySQL and sqlite
(for sqlite you must explicit the name of the fields used in the view)


Fantastic, no ?


(PS.: note that views do not improve the performance of your queries, so use them sparingly)

[11415] 3 new filters for boolean operators

, , , ...

These filters are 'et', 'ou', and 'xou' (for 'and', 'not', and 'xor').
They work like |?{' ',} :
each filter returns a space char if the condition is verified, elsewhere it returns an empty string


For example this PHP code
if ($a=='testA' OR ($b=='testB' AND $c=='testC')) {echo "OK";}

Can be translated in a template like this :
[(#A|=={testA} 
    |ou{[(#B|=={testB}
            |et{[(#C|=={testC})]})]}) OK ]

Or better
[(#B|=={testB} 
    |et{[(#C|=={testC})] 
    |ou{[(#A|=={testA})]}) OK ]

[11400] A more secure import from old SPIP versions

, , ,

This commit introduces a lot of things that make the import really secure :

  1. Create a set of tables with the old structure and a prefix not used
  2. Import data inside
  3. Update
  4. copy data to the actual site

Of course it's a beginning, a lot of things should be done :

  • Make this functionnality possible for older stable versions ([11402] for 1.8)
  • Verify that the temporary prefix isn't used
  • Interpolate between different versions for partial imports
  • Use a reload over timeout during the copy ([11402])
  • Also import plugins tables (if possible)


! INCLURE and {doublons}

, , ,

{doublons} arrays can be transmitted to included templates. #ENV can also transmit them.

These sentences are corrects :
[(#INCLURE{fond=toto}{doublons})]
<INCLURE{fond=toto}{doublons} />
spip.php?page=article&id_article=3&doublons[articles]=1,2,89,12&doublons[documents]=15,12

Note that the {doublons} are transmitted from the main template to the included one. But it's not possible to transmit the information from the included template : Especially <INCLURE /> isn't always calculated at the same time that the main template - For this reason and to keep a coherent behavior, #INCLURE keeps the same restriction for {doublons}

Example :
-------------

 <INCLURE(other_template.html){delais=0}{doublons} />
 other_template.html : 
 BOUCLE(ARTICLES){doublons}{par hasard}{0,1}

Every hit to the main template (generally cached) returns a random article that hasn't been manipulated before.


commit : http://trac.rezo.net/trac/spip/changeset/11390
announce : http://thread.gmane.org/gmane.comp.web.spip.devel/46926

What is a SPIP pipeline ? It's a hook

, ,

During the normal execution of several commands, call-outs are made to optional scripts that allow a developer to add functionality or checking. Typically, the hooks allow for a command to change the values of function arguments before any other call, and allow for a post-processing treatment that will always change the function result.

Exemple :
function prefix_treatment($flow) {
   /* add something to the flow */
   $flow .= 'This is some html code';
   return $flow;
}


plugin.xml defines the implemented hooks with a list of <pipeline> tags:
<pipeline>
 <nom>point_entree</nom>
 <action>fonction</action>
 <inclure>fichier.php</inclure>
</pipeline>


  • <nom> : name of the hook (from a list defined in ecrire/inc_version.php)
  • <action> : function name without it's prefix
  • <inclure> : file name that defines the previous function. It's name must be prefix_action


(src : http://doc.spip.org/@Tuto-Se-servir-des-points-d-entree)

Howto use an array in a template ?

, , , ...

Arrays are really usefull when you have to manipulate the same elements several times.

A new tag has been introduced with the version 1.92 :
#ARRAY{key1,value1,key2,value2...} allows the creation of a variable length table (useful for constructing a table for a #SET and/or for use with a dynamic "IN" criterion )

Short but an exemple should be helpfull..

Here is an exemple extracted from the plugin SpipBB
#SET{modos,#ARRAY}
<BOUCLE_modo_art(AUTEURS){id_article}>
   #SET{
      modos,
      #GET{modos}
        |array_merge{#ARRAY{#COMPTEUR_BOUCLE,#ID_AUTEUR}}
   }
</BOUCLE_modo_art>

<BOUCLE_art_rub(ARTICLES){id_article}>
   <BOUCLE_rub_admin(AUTEURS_RUBRIQUES)
                    {id_auteur !IN #GET{modos}}
                    {id_rubrique=#ID_RUBRIQUE}>
      <BOUCLE_aut_admin(AUTEURS){id_auteur}>
         #SET{
            modos,
            #GET{modos}
              |array_merge{#ARRAY{#COMPTEUR_BOUCLE,#_aut_admin:ID_AUTEUR}}
         }
      </BOUCLE_aut_admin>
   </BOUCLE_rub_admin>
</BOUCLE_art_rub>


  1. An empty table is created
  2. #ARRAY{#COMPTEUR_BOUCLE,#ID_AUTEUR} creates an array containing the author's id at an index that isn't used yet.
    The standard PHP function array_merge() finally does it's job : this value is now stored on the last index of the array 'modos'.
  3. Another loop completes this array with the other authors of articles that are in the same section.


Note that the PHP function is used as a filter : it's possible because it's first argument is the array to manipulate.

Of course all this can be done with PHP code inside the template. The advantage of using the tag #ARRAY is that your template is better managed by the cache.

[11355] overwrite a criterion for a specific loop only

, ,

For exemple critere_AUTEURS_recherche_dist() will overwrite the criterion recherche for the loops over AUTEURS. The priority order is :
  1. critere_TABLE_nomcrit
  2. critere_TABLE_nomcrit_dist
  3. critere_nomcrit
  4. critere_nomcrit_dist

Easter egg on the private area

, ,

"You can even create a specific template in the private area.
For exemple, this template

/squelette/prive/editer/article-23.html

is used to edit articles which are in the section number 23 (and it's subsections)
(works also to display them)"

from http://thread.gmane.org/gmane.comp.web.spip.devel/46774/focus=46786

! Custom fields are directly interpreted

, , ,

With the revision [11350], any custom field can directly be used in templates with the tags #FOO and #EDIT{foo} (with the plugin "crayons" [fr])
You don't have to change inc/modifier or specify the structure of the table : the core directly manages them.

However the private interface actually doesn't integrate these fields. You have to custom it with hooks.

(from http://thread.gmane.org/gmane.comp.web.spip.devel/46774)

[11350] any table field creates its specific tag

, , ,

The value of any field 'foo' can be displayed in your templates with #FOO -- Even if this is a field of the 'official' tables. Much more, this value can be edited in the public area with an inline content editor (actually it's still not possible in the private area) :
  • sql_showtable() is used to describe the fields (that's better than the corresponding php descriptor in tables_principales, etc..)
  • inc/modifier now uses a list of private fields (instead of a fixed list of public fields)

[11341] The form name in #ACTION_FORMULAIRE{page, formulaire}

, ,

A template formulaire/foo.html can contain another template with #INCLUDE - which can refer to it with #ACTION_FORMULAIRE{#SELF, foo}

[11289] Ajax without coding in SPIP

, , , ...

<INCLURE{fond=fond/ajax}{fond_ajax=mon_fond}{id_truc=xx}..>

includes the template and ajaxifies all it's links.

By default, the javascript variable "ajaxbloc_selecteur" is used. It transforms into ajax call each link that corresponds to the jquery selector '.pagination a,a.ajax'.

An ajax call refreshes the template's result by restauring it's #ENV, plus some parameters in the url.
When a refresh occurs, the bloc's opacity is changed to 50% and it's class to 'loading' (this div is automatically created)
The loaded part is cached on the browser with javascript. It also can be preloaded by adding the class 'preload' to the corresponding links.

That's all !

(src : http://thread.gmane.org/gmane.comp.web.spip.devel/46569)

Optimizing your SPIP server

, ,

It's in fact usefull for every website.
Here is what I do :

- Expires header and Etag :
I add this to http.conf :

# cache
ExpiresActive On
ExpiresDefault A300
ExpiresByType image/x-icon A2592000
ExpiresByType application/x-javascript A2592000
ExpiresByType text/css A2592000
ExpiresByType image/gif A604800
ExpiresByType image/png A604800
ExpiresByType image/jpeg A604800
ExpiresByType text/plain A604800
ExpiresByType application/x-shockwave-flash A604800
ExpiresByType video/x-flv A604800
ExpiresByType application/pdf A604800
ExpiresByType text/html A300
# Etags est mal calcule, donc
FileETag MTime Size

- Compression :
I use a custom .htaccess combined with php (in squelettes/css):

AddHandler application/x-httpd-php .css
php_value auto_prepend_file gzip-css.php
php_flag zlib.output_compression On

the code of gzip-css.php :
<?php
@ob_start ("ob_gzhandler");
header("Content-type: text/css; charset: UTF-8");
header("Cache-Control: must-revalidate");
$offset = 60 * 60 ;
$ExpStr = "Expires: " .
gmdate("D, d M Y H:i:s",
time() + $offset) . " GMT";
header($ExpStr);
?>

I do the same operation for javascript files (I change the header to "application/x-javascript" of course)

- I compact every CSS files in one file by using the same code of dist/squery.js.html
(of course only for one media :wink:

#CACHE{3600*100,cache-client}
#HTTP_HEADER{Content-Type: text/css; charset=iso-8859-15}
#HTTP_HEADER{Vary: Accept-Encoding}
#INCLURE{css/zero.js}
#INCLURE{css/typo.js}
#INCLURE{css/forums.js}
#INCLURE{css/documents.js}
#INCLURE{habillage.css}
#INCLURE{spip-style.css}

What optimisations do you practice ?

#URL_ECRIRE just discovered

, ,

I barely know what #URL_PAGE is.
But not #URL_ECRIRE,.. until today :wink:

This helper, like #URL_ACTION_AUTEUR, enables us to link your website to the private area.

#URL_ECRIRE{naviguer}
returns ecrire/?exec=naviguer

#URL_ECRIRE{naviguer, args}
returns ecrire/?exec=naviguer&args
(it's like #URL_PAGE in fact)

#URL_ACTION_AUTEUR{converser,args,redirectme}
returns ecrire/?action=converser&args&hash=xxx&redirect=redirectme

Combined with a filter like |parametre_url, you can do whatever you want :

For example :

<a href="#URL_PAGE{identifiants,focus=nom_inscription}&mode=(#URL_SITE_SPIP|tester_config{1comite})"
(in dist/login.html)
that returns <a href="spip.php?page=identifiants&focus=nom_inscription&mode=.."

It should possible to write
#URL_ECRIRE{forum_envoi,statut=prive&id=363&script=articles#formulaire}

but you can also use this :
[(#URL_PAGE{my_backend}|parametre_url{id_mot,#ID_MOT}|parametre_url{id_rubrique,#_:ID_RUBRIQUE})]
to generate <a href="spip.php?page=my_backend&id_mot=32&id_rubrique&..


Any idea about what to do about it ? :smile:

[11156] : new filter to exclude elements by keyword

, , ,

Nothing new in fact, just a simplification :

{!id_mot=2}
now returns all the elements that are not linked to id_mot=2 (including elements without any keyword)

FAQ : I want to update the url value after having changed the title of my article

, , ,

Long title for a frequent problem :wink: .

when a title of an article is changed, the url isn't automatically recalculated.

It's interresting if you don't want to lost backlinks, but it can be disturbing because the url may not correspond to the content of the linked page.

Here is the trick : Just clic on the link 'See online' when you display the article inside the private area. It will not only clear the cached content for this page, but it will also force the url to be recalculated according to the title field.

Howto detect if a plugin is activated ?

, , ,

in PHP :
Each plugin defines a constant corresponding to it's execution path
if (defined('_DIR_PLUGIN_XXX')){ ... }


inside a template :
#PLUGIN and conditionnal evaluation does your job !
[(#PLUGIN{XXX}) doSomething ]

A lot of arguments for a tag

,

They can sometimes be concatenated into a unique argument list :

[(#MODELE{emb}{autostart=true}{this=1}{that=anything})]
#MODELE{emb}{autostart=true,this=1,that=anything}
[(#INCLURE{something}{id_xx=0}{env}{truc=toto})]


All these sentences are corrects. But you can't write :

#INCLURE{something}{id_xx=0,env,truc=toto}


because it's inherited from syntax of the <INCLURE>
Note that the first argument of a tag can't be a list.

SPIP 1.9.2d is available !

,

1.9.2d is a bug-fix update. It is advisable to upgrade to this version which should not have any visible impact for the visitors to your site if you are already using a version 1.9.2 (a,b or c).
You can download this version at http://www.spip.net/en_article3103.html.

The changes are:

For authors and admins:
  • correction of an inconsistency in the managing of the date of attached documents (date/time on creation, but only date thereafter);
  • correction of a bug on the sections menu which hid some of them (bug #1113);
  • avoid javascript error when loading a page and the mouse was moved too quickly;
  • the graphic configuration and site address are no longer overwritten when restoring a backup, as they are linked to the server;
  • the correct display of successive screenshots in the statistics;
  • updated Indonesian translation;
  • correction of a bug on the permissions on modification of sites syndicated by restricted admins;
  • correction of several bugs to do with the permissions on logos;
  • correction of an SQL bug on the section selector which made it unusable on big sites (sections are now sorted {par num titre, titre};
  • correction of a bug which could allow a restricted admin to move a published article to a section of which he/she is not an administrator.


For developers of plugins:
  • $GLOBALS['_INC_PUBLIC'] replaces the constant _INC_PUBLIC.
  • It is incremented in each template inclusion. This is used in the plugin "balise_session" that reproduces a new session mechanism introduced in the development version of SPIP: Tipically, if you want to create templates which results depend on the user, you actually needn't include session.php: a specific tag, #SESSION, automatically handles the cleaning process of the cached files -- even in statical includes like models --
  • Correction of the cache cleaning process in CRON (it sometimes failed when a bot visited the site)
  • url_de_base() can now be used in mes_options.php
  • This release Fixes a missing inclusion which could make the function autoriser_voir_dist() crash.
  • recuperer_page() properly takes care of https uri (If php was compiled with the support of ssl)


Thanks Paolo for this translation of the original announcement by Cédric.

[11094] cache overflow is still a reality

,

When the cron doesn't manage to empty correctly the cache, the site crashes rapidly. The only solution then is to empty completly the cache directory.

It's what does this commit, but it's a poor patch with a huge side effect : the cache delay specified in a template isn't really taken into account because the cached file is erased rapidly

There is no doubt that a better solution will come soon

note :
Cache explosion was also partially corrected in :


-- EDIT (01/28/2008) --
This problem is almost corrected in the version 1.9.2d, as it is explained in the changelog of this version

Howto declare an empty array in SPIP ?

, ,

The only solution is to use
#SET{rubriques, #ARRAY}

If the array is initialised, there is always a default element inside :
#SET{liste_membres,#ARRAY{0}}
creates a PHP array(0=>'0')

[10805] private area : object pages in templates

, , ,

Big change in the private area API :

afficher_contenu_objet() is simplified and know uses a customizable template for every (standard?) table.
The result of this template uses a pipeline ('afficher_contenu_objet'), and so plugins can modify it .

This commit creates a directory 'dist/contenu/' that contains article.html, breve.html, etc.
Really usefull for customisation of the private area, no ?

[10829] scaffolding for every table

,

Scaffolding is a great feature that enables to view the content of the non-standard spip tables.
When you are the website admin (member of _ID_WEBMESTRES), you can write :
http...?page=table:tableName

Actually, it's still minimal but quite functionnal :
- a table with as many columns as of the SQL table fields
- The tag #PAGINATION enables to scroll lines per block of ten
- The first (or last) row of a table enables the table to be sorted depending on the selected column, either ascending or descending order. The field type is taken into account in this order.
- The url can filter one or more values for every field, simply by specifying "&fieldname=.."
- For each field described in SQL as a reference to another table, a link to another scaffolding for this table is specified.

source : [10996] and [10645]

[11033] INCLURE

,

Maybe a detail, but now a more "W3C_like" compliant form of INCLURE is accepted :
<INCLURE{fond=foo} />

[11068] optimisation for empty loops

,

Empty loops are no longer tested since the result is known.
It's really helpful for loops that calculate only 'doublons' or counters : they return nothing, so the generated code is better.

We can now write :

<BOUCLEnom(type) />#TOTAL_BOUCLE<//Bnom>

instead of

<BOUCLEnom(type)>
</BOUCLEnom>
#TOTAL_BOUCLE
</Bnom>

source : [11068]