CMS Hooks API

Introduction

The Content Management System Hooks (CMS Hooks) API is for users wishing to display various output from a WIKINDX database into a CMS (Content Management System). It requires some minimal configuration in the Admin > Configure panel.

The following assumes the path to the WIKINDX is https://wikindx.test/ – if not, adjust the path accordingly.

With a browser go to the page https://wikindx.test/cmsprint.php. If you get the message “CMS feature disabled”, you still have to unlock the CMS feature. If you get the message “Unknown action” you are ready use it.

In the examples below, we assume you use a CMS written in PHP, as most are, but the approach remains valid for any program capable of using the HTTP protocol.

In the appendix you will find two basic functions to help you write your first queries. This code uses the cUrl extension (to be activated in the php.ini configuration file if it is not done).

It is strongly advised not to use file_get_contents() or fopen() to make your requests (allow_url_fopen option need to be activated for that). These functions do not provide a means of debugging the code and are susceptible to attacks allowing the execution of arbitrary code. That’s why we provide the curl_get() function as an appendix.

During development you can check that a response is correct by checking cUrl and HTTP error codes. When all goes well cUrl returns code 0 and HTTP 200. It is rare that cUrl returns an error unless its configuration is not adapted to your network (e.g. mandatory proxy). However, you may frequently encounter the following HTTP errors:

  • 400: Bad Request, the url does not respect the expected semantics and the service cannot respond (fix your query parameters).
  • 403: Forbidden, the CMS feature is disabled (enable it)).
  • 407: Proxy Authentication Required (add proxy params to curl_get() and curl_post()).
  • 408: Request Timeout, the computation of the response is too long (request less data).
  • 500: Internal Server Error, WIKINDX crashed (seems you found a bug, contact us).

The CMS Hooks API has two family of queries:

  • returning single or multiple resources from a WIKINDX for display in a CMS.
  • parsing and formatting of citations in a block of text sent from the CMS to the WIKINDX.

Basics of querying

The API only uses two HTTP verbs GET and POST.

Sending a GET or POST request consists of calling a URL with parameters called queryString. The queryString first parameter (case sensitive) is always preceded by a question mark, the following by an ampersand. The name of a parameter is separated from its value by an equal sign. When special characters appear they must be escaped (this should not be the case because the expected values are numeric in our case).

Examples:

https://wikindx.test/cmsprint.php?param1=value1

https://wikindx.test/cmsprint.php?param1=value1&param2=value2

https://wikindx.test/cmsprint.php?param1=value1&param2=value2&param3=it%27s+value+3

When the request uses the POST verb, we also add a body encoded with the method application/x-www-form-urlencoded (RFC1738). This is information that we want the server to process in addition to parameters. The curl_post() function is written to support this encoding transparently.

The rest of the document describes the verb, the combinations of parameters and the body to send, to obtain the desired result.

Querying generic parameters

The following parameters are valid in all queries.

  1. action is required and must have valid values (case sensitive) ; This parameter indicates what type of response you expect. The values are described later.

  2. mimetype is optional and can take values (case sensitive) php (default) or json. This parameter conditions the format of the data returned. To read serialized PHP, use the unserialize() function, for json use json_decode().

  3. bibStyle is optional and select the bibliographic style used for formatting resources. If this parameter is omitted or its value is wrong the style configured in admin panel will be used. Accepted values are the identifier of a style in uppercase. The APA style is always available, the other styles delivered with WIKINDX may not be installed (ABNT, BRITISHMEDICALJOURNAL, CFB, CHICAGO-AD, CHICAGO-FTHARVARD, IEEE, MLA, TURABIAN, WIKINDX).

  4. language is optional and select your preferred locale used for formatting resources. If this parameter is omitted or its value is wrong the locale configured in the style will be used. Example of accepted locale: en, fr, de_AT, etc.

Returning single or multiple WIKINDX resources

In all cases, the return from WIKINDX comprises zero, one or more resources matching the queryString parameters inside an array.

We describe here the operation of the parameters common to these actions, then the actions and the exceptions if necessary with examples.

  1. action is required and must have valid values among : getAll, getResource, getCategory, getSubCategory, getKeyword, getCreator, getPublisher, getCollection, getAbstract, getNotes, getQuote, getParaphrase, getMusing, getRecent.

  2. id is required, excepting getAll and getRecent actions, and must have valid values. The id you wish to use may be found directly in WIKINDX (if you’ve set your WIKINDX Preferences to view the CMS pop-up window). You can specify multiple ids separated by commas.

  3. limit is optional. e.g. &limit=10 in the queryString will limit the results of any list to 10. limit will be ignored if action=getResource or action=getAll. The default is unlimited, which is not really unlimited because requests have a maximum size and execution time that depends on the server configuration of requested WIKINDX.

  4. order is optional. e.g. order=year in the queryString will display a list ordered by publication year. Possible values are creator, year, title, and timestamp. The default is creator. getAll action always use timestamp order.

  5. When using getKeyword, getCategory or getCreator, you may have a further parameter of sqlMethod=and which allows you to return results, for example, where each resource belongs to all requested categories. By default, the resources in the result match any one of the requested categories. Ditto for keywords and creators.

When getting notes, quotes, paraphrases or musings, only public ones are returned.

Response format

The output is a string representing serialized PHP array or JSON array.

Example of JSON response:

{"95":"de Sainte-Marie, A., & du Fourny, H. (1733). <em>Histoire g\u00e9n\u00e9alogique et chronologique de la maison royale de france et des grands officiers de la couronne, de la maison du roy et des anciens barons du royaume<\/em>. Vol. 7. 75 - Paris: Compagnie des Libraires."}

Example of PHP response:

a:1:{i:95;s:263:"de Sainte-Marie, A., & du Fourny, H. (1733). <em>Histoire généalogique et chronologique de la maison royale de france et des grands officiers de la couronne, de la maison du roy et des anciens barons du royaume</em>. Vol. 7. 75 - Paris: Compagnie des Libraires.";}

To access this array, you will need to use the following code:

$array = unserialize($response);
$array = json_decode($response, TRUE);

The contents of $array may be like the following example:

	[13] => Back, M., &amp; Des, D. (1996). Micro-narratives in sound design: Context and caricature in waveform manipulation. Retrieved March 12, 2004, from <a href="http://www2.hku.nl/~audiogam/ag/articles/micronaratives.htm" target="_blank">http://www2.hku.nl/~aud&nbsp;...&nbsp;cles/micronaratives.htm</a>.
	[54] => Carr, D. (2003). Play dead: Genre and affect in silent hill and planescape torment. <em>Game Studies</em><em>, 3</em>(1). Retrieved September 16, 2003, from <a href="http://www.gamestudies.org/0301/carr/" target="_blank">http://www.gamestudies.org/0301/carr/</a>.
	[2] => Chion, M. (1992). Wasted words. In R. Altman (Ed.), <em>Sound Theory Sound Practice</em> (pp. 104&ndash;110). New York: Routledge.
	[103] => Chion, M. (1994). <em>Audio-vision: Sound on screen</em> (C. Gorbman, Trans.) New York: Columbia University Press.
	[4] => Truppin, A. (1992). And then there was sound: The films of Andrei Tarkovsky. In R. Altman (Ed.), <em>Sound Theory Sound Practice</em> (pp. 235&ndash;248). New York: Routledge.

Note that, depending upon the bibliographic style chosen, the results may contain HTML tags and entities (as in the above example). The key of each array member is the resource ID.

You can then loop through this array in order to format and print the individual items as you wish. An example might be:

foreach($array as $resourceId => $item)
{
    print $item . "<br>";
}

Action getAll : return all resources

HTTP verb: GET

Request: https://wikindx.test/cmsprint.php?mimetype=json&action=getAll

Example of JSON response:

{
  "12": "Saffroy, G. (1970). <em>Bibliographie généalogique, héraldique et nobiliaire de la France des origines à nos jours, imprimés et manuscrits</em>. 75 - Paris: Saffroy.",
  "39": "Barré de Saint-Venant, R. (1969). <em>Dictionnaire topographique, historique, biographique, généalogique et héraldique du vendômois et de l'arrondissement de vendôme</em>. Vendôme, 41: Société archéologique, scientifique et littéraire du Vendômois. (Original work published 1912-1917).",
  "73": "Votre Généalogie. (2008). Votre généalogie n° 27. <em>Votre Généalogie</em>, <em>27</em>.",
  "92": "de Sainte-Marie, A., & du Fourny, H. (1727). <em>Histoire généalogique et chronologique de la maison royale de france et des grands officiers de la couronne, de la maison du roy et des anciens barons du royaume</em>. Vol. 3. 75 - Paris: Compagnie des Libraires.",
  "94": "de Sainte-Marie, A., & du Fourny, H. (1730). <em>Histoire généalogique et chronologique de la maison royale de france et des grands officiers de la couronne, de la maison du roy et des anciens barons du royaume</em>. Vol. 6. 75 - Paris: Compagnie des Libraires.",
  "95": "de Sainte-Marie, A., & du Fourny, H. (1733). <em>Histoire généalogique et chronologique de la maison royale de france et des grands officiers de la couronne, de la maison du roy et des anciens barons du royaume</em>. Vol. 7. 75 - Paris: Compagnie des Libraires."
}

Action getResource : return one or more resources requested by resource id

HTTP verb: GET

Request: https://wikindx.test/cmsprint.php?mimetype=json&action=getResource&id=95

Example of JSON response:

{
  "95": "de Sainte-Marie, A., & du Fourny, H. (1733). <em>Histoire généalogique et chronologique de la maison royale de france et des grands officiers de la couronne, de la maison du roy et des anciens barons du royaume</em>. Vol. 7. 75 - Paris: Compagnie des Libraires."
}

Action getCategory : return one or more resources of a category requested by category id

HTTP verb: GET

Request: https://wikindx.test/cmsprint.php?mimetype=json&action=getCategory&id=4

Example of JSON response:

{
  "92": "de Sainte-Marie, A., & du Fourny, H. (1727). <em>Histoire généalogique et chronologique de la maison royale de france et des grands officiers de la couronne, de la maison du roy et des anciens barons du royaume</em>. Vol. 3. 75 - Paris: Compagnie des Libraires."
}

Action getSubcategory : return one or more resources of a subcategory requested by subcategory id

HTTP verb: GET

Request: https://wikindx.test/cmsprint.php?mimetype=json&action=getSubcategory&id=2

Example of JSON response:

{
  "94": "de Sainte-Marie, A., & du Fourny, H. (1730). <em>Histoire généalogique et chronologique de la maison royale de france et des grands officiers de la couronne, de la maison du roy et des anciens barons du royaume</em>. Vol. 6. 75 - Paris: Compagnie des Libraires."
}

Action getKeyword : return one or more resources having a keyword requested by keyword id

HTTP verb: GET

Request: https://wikindx.test/cmsprint.php?mimetype=json&action=getKeyword&id=12

Example of JSON response:

{
  "73": "Votre Généalogie. (2008). Votre généalogie n° 27. <em>Votre Généalogie</em>, <em>27</em>."
}

Action getCreator : return one or more resources of a creator requested by creator id

HTTP verb: GET

Request: https://wikindx.test/cmsprint.php?mimetype=json&action=getCreator&id=143

Example of JSON response:

{
  "12": "Barré de Saint-Venant, R. (1970). <em>Bibliographie généalogique, héraldique et nobiliaire de la France des origines à nos jours, imprimés et manuscrits</em>. 75 - Paris: Saffroy.",
  "39": "Barré de Saint-Venant, R. (1969). <em>Dictionnaire topographique, historique, biographique, généalogique et héraldique du vendômois et de l'arrondissement de vendôme</em>. Vendôme, 41: Société archéologique, scientifique et littéraire du Vendômois. (Original work published 1912-1917)."
}

To display up to 5 resources by two particular creators (where they are co-authors), ordered by publication year:

HTTP verb: GET

Request: https://wikindx.test/cmsprint.php?mimetype=json&action=getCreator&id=4,5&limit=5&order=year&sqlMethod=and

Example of JSON response:

{
  "5": "Bernard, G., Escalle, E., Maurin, I. (1976). <em>Maurs au fil des siècles: Des origines à 1789</em>.",
  "6": "Bernard, G., Escalle, E., Maurin, I. (1988). <em>Guide des recherches sur l'histoire des familles</em>.",
  "9714": "Bernard, G., Escalle, E., Maurin, I. (1987). <em>Les familles protestantes en france : xvie siècle - 1792 : guide des recherches biographiques et généalogiques</em>. 75 - Paris: Archives de France.",
  "15149": "Bernard, G., Escalle, E., Maurin, I., G. (1990). <em>Les familles juives en france : xvie siècle-1815 : guide des recherches biographiques et généalogiques</em>. 75 - Paris: Archives Nationales.",
  "19999": "Bernard, G., Escalle, E., Maurin, I., Pariset, J.-D., & Zuber, H. (1987). <em>Les familles protestantes en france : xvie siècle-1792 : guide des recherches biographiques et généalogiques</em>. 75 - Paris: Archives Nationales."
}

Action getPublisher : return one or more resources requested by publisher id

HTTP verb: GET

Request: https://wikindx.test/cmsprint.php?mimetype=json&action=getPublisher&id=42

Example of JSON response:

{
  "75": "Tanguay, C. (1871). <em>Dictionnaire généalogique des familles canadiennes depuis la fondation de la colonie jusqu'à nos jours</em>. Vol. 1. Québec: Senécal.",
  "76": "Tanguay, C. (1886). <em>Dictionnaire généalogique des familles canadiennes depuis la fondation de la colonie jusqu'à nos jours</em>. Vol. 2. Québec: Senécal.",
  "77": "Tanguay, C. (1886). <em>Dictionnaire généalogique des familles canadiennes depuis la fondation de la colonie jusqu'à nos jours</em>. Vol. 3. Québec: Senécal.",
  "78": "Tanguay, C. (1888). <em>Dictionnaire généalogique des familles canadiennes depuis la fondation de la colonie jusqu'à nos jours</em>. Vol. 5. Québec: Senécal.",
  "79": "Tanguay, C. (1889). <em>Dictionnaire généalogique des familles canadiennes depuis la fondation de la colonie jusqu'à nos jours</em>. Vol. 6. Québec: Senécal.",
  "80": "Tanguay, C. (1890). <em>Dictionnaire généalogique des familles canadiennes depuis la fondation de la colonie jusqu'à nos jours</em>. Vol. 7. Québec: Senécal."
}

Action getCollection : return one or more resources of a collection requested by collection id

HTTP verb: GET

Request: https://wikindx.test/cmsprint.php?mimetype=json&action=getCollection&id=13

Example of JSON response:

{"125":"Collectif. <em>Les monographies des instituteurs de seine-et-oise<\/em>. Unpublished manuscript."}

Action getAbstract : return the abstract of one or more resources requested by resource id

HTTP verb: GET

Request: https://wikindx.test/cmsprint.php?mimetype=json&action=getAbstract&id=242

Example of JSON response:

{
  "10": "Louis-Etienne SAINT-DENIS (alias le mameluck ALI). Entr&#233; en 1806 au service de Napol&#233;on, Louis-Etienne Saint-Denis (n&#233; &#224; Versailles en 1788) passe en d&#233;cembre 1811 au service int&#233;rieur comme second \"mameluck\". C'est par la volont&#233; de l'Empereur qu'il s'appellera d&#233;sormais Ali. Faux \"mameluck\" mais vrai t&#233;moin, Ali note tout par le menu, depuis la campagne de Russie jusqu'&#224; la mort de l'Empereur - en passant par le premier exil &#224; l'&#238;le d'Elbe, la d&#233;faite des arm&#233;es fran&#231;aises &#224; Waterloo et l'embarquement pour Sainte-H&#233;l&#232;ne. Comme l'a &#233;crit Jean-Paul Kauffmann : \"Ali est la m&#233;moire visuelle de la captivit&#233;.\" Publi&#233;s pour la premi&#232;re fois en 1926 et jamais r&#233;&#233;dit&#233;s depuis, les Souvenirs du Mameluck Ali sur l'Empereur Napol&#233;on constituent un t&#233;moignage unique sur l'homme qui a marqu&#233; l'Histoire &#224; tout jamais. Ouvrage sinc&#232;re et captivant !"
}

Action getNotes : notes of one or more resources requested by resource id

HTTP verb: GET

Request: https://wikindx.test/cmsprint.php?mimetype=json&action=getNotes&id=74,75,76

Example of JSON response:

{"74":"17 fascicules","75":"Qu&#233;bec","76":"Qu&#233;bec"}

Action getQuote : return quotes of one or more resources requested by resource id

HTTP verb: GET

Request: https://wikindx.test/cmsprint.php?mimetype=json&action=getQuote&id=755,22830

Example of JSON response:

{
  "755": {
    "1": "Depuis que le Reich hitlérien a disparu, avec les camps de concentration qui en étaient une caractéristique essentielle, la littérature sur ce sujet n'a pas cessé d'être importante, en Allemagne même, et dans les autres pays concernés, pays européens, États-Unis ou Israël."
  },
  "22830": {
    "10": "Martin est le nom le plus répandu en France",
    "12": "Petit est un patronyme très courant en France."
  }
}

The response is an array of arrays. Keys of the main array are resource ids and subarrays are quotes where the key is a quote id and the value is the quote.

Action getParaphrase : return paraphrases of one or more resources requested by resource id

HTTP verb: GET

Request: https://wikindx.test/cmsprint.php?mimetype=json&action=getParaphrase&id=915

Example of JSON response:

{
  "915": {
    "8": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut leo nibh, iaculis quis nunc scelerisque, pellentesque volutpat arcu. Phasellus tellus leo, accumsan eget dolor lacinia, maximus facilisis ex. Donec sodales vel ipsum sed fringilla. Pellentesque quis suscipit dolor. Fusce eleifend congue eros elementum commodo. Curabitur placerat quam at eros facilisis, eu volutpat nunc dignissim. Praesent aliquet lectus mauris, ut feugiat dolor sagittis vitae."
  }
}

Action getMusing : return musings of one or more resources requested by resource id

HTTP verb: GET

Request: https://wikindx.test/cmsprint.php?mimetype=json&action=getMusing&id=11520

Example of JSON response:

{
  "22830": {
    "6": "Cras non sodales ex. Curabitur pellentesque metus facilisis consequat efficitur. Sed vitae turpis non velit maximus cursus eu blandit nunc. Fusce vehicula risus rutrum posuere molestie.",
    "7": "Vestibulum in laoreet leo, vitae dictum sapien. Fusce mollis augue mauris, eget sodales metus ullamcorper at."
  }
}

The response is an array of arrays. Keys of the main array are resource ids and subarrays are musings where the key is a quote id and the value is the musing.

Action getRecent : return the most recent added/edited resources

To display the 10 most recently added resources:

HTTP verb: GET

Request: http://wikindx.test/cmsprint.php?mimetype=json&action=getRecent&limit=3

Example of JSON response:

{
  "21602": "Anonyme. (2008). <em>Saint vincent des landes (44) - décès de 1670 à 1802</em>. 35 - Grand Fougeray: Histoire et Généalogie.",
  "22830": "<em>Les vieux noms de la france de l’ouest et les familles d’origine française au delà des mers</em>. (1954). Vol. 868. Beauchênes.",
  "22832": "<em>Bretet 12: Uie</em>. January 24 2020. Edison."
}

To display at most 15 resources added within the last 5 days:

HTTP verb: GET

Request: http://wikindx.test/cmsprint.php?mimetype=json&action=getRecent&limit=7&days=5

Example of JSON response:

{
  "21602": "Anonyme. (2008). <em>Saint vincent des landes (44) - décès de 1670 à 1802</em>. 35 - Grand Fougeray: Histoire et Généalogie.",
  "22827": "France, M. D. (1958). <em>Histoire de la famille de france : venue d’artois en champagne, 1415-1957. [avant-propos de michel de france.]</em>. Vol. 865. 42 -\tSaint-Just-la-Pendue: Imprimerie Chirat.",
  "22828": "Le Blant, R. (1955). <em>Robert le blant. nobiliaire de béarn : tome 2</em>. Vol. 866. 40 -\tDax: Impr. de Dumolia.",
  "22829": "<em>Recueil généalogique de la bourgeoisie ancienne. deuxième série</em>. (1955). Vol. 867. 75 -\tParis: Editions S.G.A.F.",
  "22830": "<em>Les vieux noms de la france de l’ouest et les familles d’origine française au delà des mers</em>. (1954). Vol. 868. Beauchênes.",
  "22831": "Vrignault, H.-Y.-F. (1954). <em>Les enfants de louis xv, descendance illégitime</em>. Vol. 869. 75 - Paris: Perrin.",
  "22832": "<em>Bretet 12: Uie</em>. January 24 2020. Edison."
}

Parsing and formatting citations in text

WIKINDX may be used to format a series of citations within a block of CMS text that uses the CMS replacement tags. The CMS replacement tag may be automatically generated for pasting into the CMS text by using the WIKINDX CMS pop-up window if you have set the CMS hyperlink to display in your WIKINDX preferences. The citation style, by default, uses the style set in the WIKINDX admin panel.

If your CMS text block containing the replacement tags is:

Chion states that:  "Blah, blah, blah" {ADD_BIB_ITEM:3:314} but in a later article corrects this by saying:  "Bleah, bleah, bleah" {ADD_BIB_ITEM:89:22-23}.

the output from WIKINDX (assuming the current style is APA) may be:

Chion states that:  "Blah, blah, blah" (p.314) but in a later article corrects this by saying:  "Bleah, bleah, bleah" (Chion 2001, 22-23).

The replacement tag may have further parameters: it is recommended to use the CMS replacement tag generator in WIKINDX for greatest accuracy.

There are several steps in creating the replacement tag code in your CMS, sending the text block to WIKINDX and receiving it back:

  1. For efficiency, first check to see if there are any replacement tags in the text block and, if not, return immediately. For example:
if (strpos($text, "{ADD_BIB_ITEM:") === FALSE)
{
    return;
}
  1. Use preg_replace() to reformat your particular CMS replacement tags to a format WIKINDX will recognize (using [cite]...[/cite]). For example, with the CMS replacement tags in the example above, you should use:
$text = preg_replace("/\{ADD_BIB_ITEM:(.*)\}/Ui", "[cite]$1[/cite]", $text);

Using the example above, this code will produce:

Chion states that:  "Blah, blah, blah" [cite]3:314[/cite] but in a later article corrects this by saying:  "Bleah, bleah, bleah" [cite]89:22-23[/cite].
  1. Write the new $text to a temporary file on your web server.

  2. Send a POST to WIKINDX where you give the text to parse as a value of text body parameter.

$response_array = curl_post("https://wikindx.test/cmsprint.php?action=parseText", ["text" => "Belle journée [cite]22827[/cite] [cite]22828[/cite] pour une promenade [footnote]J'aime particuliérement le bord du lac[/footnote]"]);
  1. Print $string back to your CMS.
echo $response_array["response"];

Note the following:

The response will contain not only the formatted text block but will also contain an appended bibliography of the citations in the text. Where the current style is an in-text citation style such as APA, this bibliography is separated by <br><br> – if your CMS uses similar HTML code for line breaks and you wish to be able to split this bibliography from the text for some reason, you should replace all occurrences of <br> with a unique string prior to sending it to the WIKINDX and then split the result on <br><br> before reverting that unique string back to <br> and finally printing the result back to the CMS. If the current style is a style using footnotes such as Chicago, the WIKINDX result contains the formatted text, the required footnote citations and the appended bibliography. Splitting the WIKINDX result on <br><br> will produce an array of three members, the first being the text block, the second being the footnotes and the third being the bibliography. For example, you might use the following code:

$text = preg_replace("/\{ADD_BIB_ITEM:(.*)\}/Ui", "[cite]$1[/cite]", $text);
$text = str_replace('<br>', 'IAMAUNIQUESTRING', $text);

$response_array = curl_post("https://wikindx.test/cmsprint.php?action=parseText", ["text" => $text]);

$split = preg_split("/(<br \/>){2,2}/i", $response_array["response"]);
$text = str_replace('IAMAUNIQUESTRING', '<br>', $split[0]);
$footnotes = $split[1];
$bibliography = $split[2];

Annex

<?php

$cms_url = "http://wikindx.test/cmsprint.php?action=parseText";

$response_array = curl_get($cms_url);

// Print the whole array
//echo print_r($response_array);

// Print only the response
echo $response_array["response"];

/**
 * Send a GET HTTP request
 *
 * @param string $url - the url
 * @param bool $verbose_mode Set to TRUE to get raw traces
 *
 * @return array
 */
function curl_get($url, $verbose_mode = FALSE)
{
    $ch = curl_init();

    curl_setopt($ch, CURLOPT_URL, $url ?? "");

    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, FALSE);

    curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
    curl_setopt($ch, CURLOPT_BINARYTRANSFER, TRUE);

    // Disables certificate verification and proxy usage
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
    curl_setopt($ch, CURLOPT_PROXY, NULL);

    // Timeout de la connexion en secondes
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);

    // Timeout de l'exécution en secondes
    curl_setopt($ch, CURLOPT_TIMEOUT, 60);

    curl_setopt($ch, CURLOPT_VERBOSE, $verbose_mode);

    $response = curl_exec($ch);
    if ($response === FALSE)
    {
        $response = "";
    }

    $errno_http = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
    $errmsg_http = http_strerror($errno_http);

    $errno_curl = curl_errno($ch);
    $errmsg_curl = curl_strerror($errno_curl);

    // Since PHP 8.0 the curl_close() function no longer has an effect
    if (version_compare(PHP_VERSION, '8.0.0', '<'))
    {
        curl_close($ch);
    }

    return [
        "errno_curl" => $errno_curl,
        "errmsg_curl" => $errmsg_curl,
        "errno_http" => $errno_http,
        "errmsg_http" => $errmsg_http,
        "response" => $response,
    ];
}

/**
 * Send a POST HTTP request
 *
 * @param string $url - the url
 * @param bool $verbose_mode Set to TRUE to get raw traces
 *
 * @return array
 */
function curl_post($url, $data = NULL, $verbose_mode = FALSE)
{
    $ch = curl_init();

    curl_setopt($ch, CURLOPT_URL, $url ?? "");
    curl_setopt($ch, CURLOPT_POST, TRUE);

    if (!is_null($data))
    {
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
    }

    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, FALSE);

    curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
    curl_setopt($ch, CURLOPT_BINARYTRANSFER, TRUE);

    // Disables certificate verification and proxy usage
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
    curl_setopt($ch, CURLOPT_PROXY, NULL);

    // Connection timeout in seconds
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);

    // Execution timeout in seconds
    curl_setopt($ch, CURLOPT_TIMEOUT, 60);

    curl_setopt($ch, CURLOPT_VERBOSE, $verbose_mode);

    $response = curl_exec($ch);
    if ($response === FALSE)
    {
        $response = "";
    }

    $errno_http = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
    $errmsg_http = http_strerror($errno_http);

    $errno_curl = curl_errno($ch);
    $errmsg_curl = curl_strerror($errno_curl);

    // Since PHP 8.0 the curl_close() function no longer has an effect
    if (version_compare(PHP_VERSION, '8.0.0', '<'))
    {
        curl_close($ch);
    }

    return [
        "errno_curl" => $errno_curl,
        "errmsg_curl" => $errmsg_curl,
        "errno_http" => $errno_http,
        "errmsg_http" => $errmsg_http,
        "response" => $response,
    ];
}

/**
 * Return the english name associated with an HTTP error code
 *
 * @param int|string $errno - HTTP error code
 *
 * @return string
 */
function http_strerror($errno)
{
    if (is_string($errno) && is_numeric)
    {
        if (is_numeric($errno))
        {
            $errno = intval($errno);
        }
        else
        {
            $errno = 0;
        }
    }

    $http_status_codes = [
        // 1xx informational response
        100 => "Continue",
        101 => "Switching Protocols",
        102 => "Processing",
        103 => "Early Hints",

        // 2xx success
        200 => "OK",
        201 => "Created",
        202 => "Accepted",
        203 => "Non-Authoritative Information",
        204 => "No Content",
        205 => "Reset Content",
        206 => "Partial Content",
        207 => "Multi-Status",
        208 => "Already Reported",
        226 => "IM Used",

        // 3xx redirection
        300 => "Multiple Choices",
        301 => "Moved Permanently",
        302 => "Found",
        303 => "See Other",
        304 => "Not Modified",
        305 => "Use Proxy",
        306 => "Switch Proxy",
        307 => "Temporary Redirect",
        308 => "Permanent Redirect",

        // 4xx client errors
        400 => "Bad Request",
        401 => "Unauthorized",
        402 => "Payment Required",
        403 => "Forbidden",
        404 => "Not Found",
        405 => "Method Not Allowed",
        406 => "Not Acceptable",
        407 => "Proxy Authentication Required",
        408 => "Request Timeout",
        409 => "Conflict",
        410 => "Gone",
        411 => "Length Required",
        412 => "Precondition Failed",
        413 => "Payload Too Large",
        414 => "URI Too Long",
        415 => "Unsupported Media Type",
        416 => "Range Not Satisfiable",
        417 => "Expectation Failed",
        418 => "I'm a teapot",
        421 => "Misdirected Request",
        422 => "Unprocessable Entity",
        423 => "Locked",
        424 => "Failed Dependency",
        425 => "Too Early",
        426 => "Upgrade Required",
        428 => "Precondition Required",
        429 => "Too Many Requests",
        431 => "Request Header Fields Too Large",
        451 => "Unavailable For Legal Reasons",

        // 5xx server errors
        500 => "Internal Server Error",
        501 => "Not Implemented",
        502 => "Bad Gateway",
        503 => "Service Unavailable",
        504 => "Gateway Timeout",
        505 => "HTTP Version Not Supported",
        506 => "Variant Also Negotiates",
        507 => "Insufficient Storage",
        508 => "Loop Detected",
        510 => "Not Extended",
        511 => "Network Authentication Required",

        // DeepL specific code
        456 => "Quota exceeded",
        529 => "Too many requests",
    ];

    return $http_status_codes[$errno] ?? "";
}

History

  • WIKINDX v9, 2022 – complete rewrite for 6.6.0 version.
  • WIKINDX v8, 2021 – Always return arrays or HTTP error code.
  • WIKINDX v7, 2021 – Rework metadata format.
  • WIKINDX v6, 2021 – Remove parseSql() call and rework metadata format.
  • WIKINDX v5, 2016 – Added language parameter.
  • WIKINDX v4, 2011 – Part 2 added below.