In questo post mostro un semplice snippet per estrarre un archivio Tar in una directory temporanea.
$phar = new PharData('nome-archivio.tar');
//Estraggo tutti i files posizionandoli in /tmp/
$phar->extractTo('/tmp/', null, true);
$phar = new PharData('nome-archivio.tar');
//Estraggo tutti i files posizionandoli in /tmp/
$phar->extractTo('/tmp/', null, true);
$_DIR = '/var/www/html/images/';
$images_array = glob($_DIR . '*.jpg');
foreach ($images_array as $image) {
echo $image;
}
private Size currSize;2. Aggiungere nel costruttore, dopo InitializeComponent()
this.AutoScaleMode = AutoScaleMode.None; currSize = this.Size;3. Aggiungere la seguente funzione
private void autoscale()
{
Font tempFont;
SizeF ratio = SizeF.Empty;
//calculate resizing ratio
ratio = new SizeF((float)this.Width / currSize.Width, (float)this.Height / currSize.Height);
//loop through all controls and scale them
foreach (Control c in this.Controls)
{//Get current font size, Scale object and scale font
tempFont = new Font(c.Font.Name,
c.Font.SizeInPoints * ratio.Width * ratio.Height);
c.Scale(ratio);
c.Font = tempFont;
}
//update current size
currSize = this.Size;
}
4. Utilizzare la funzione precedente nell'evento SizeChanged della windows form
private void Form1_SizeChanged(object sender, EventArgs e)
{
autoscale();
}
deb http://apt.izzysoft.de/ubuntu generic universe
wget http://apt.izzysoft.de/izzysoft.asc
sudo apt-key add izzysoft.asc4. Installare monitorix
sudo apt-get update sudo apt-get install monitorix
http://localhost:8080/monitorix/
In principio fu l'include (o il require) di tanti file php che contenevano funzioni.Ed ora? Adesso il Php è un linguaggio molto più maturo, dotato di namespace, che permettono a classi con lo stesso nome di coesistere (con namespace diversi) all'interno dello stesso progetto. In questo modo, includere una libreria di terze parti progettata a namespace non comporta più problemi di omonimia di classi.
Poi vennero le classi, incluse a mano una per una.
//Autoloading classes
spl_autoload_register(function($className)
{
//Obtain the pure class name
$pureClassName = getRealClassName($className);
//Build the path
$namespace = getNameSpace($className);
if(file_exists($namespace.'/'.$pureClassName.'.php')) {
include_once($namespace.'/'.$pureClassName.'.php');
}
});
function getRealClassName($fullClassName) {
//Explode class name
$classNameArray = explode('\\',$fullClassName);
//Obtain the pure class name
return end($classNameArray);
}
function getNameSpace($fullClassName) {
//Explode class name
$classNameArray = explode('\\',$fullClassName);
//Remove the pure class name
array_pop($classNameArray);
//Remove the main namespace (first)
array_shift($classNameArray);
//Build the path
$namespace = implode('/', $classNameArray);
return $namespace;
}
Breve spiegazione: nel caso il Php non trovi una classe, tenta una inclusione automatica, cercando il file posizionato nel percorso indicato dal namespace (stessa struttura delle cartelle quindi) e chiamato come il nome della classe, con estensione php. Le due funzioni getRealClassName() e getNameSpace() sono semplici funzioni che interpretano il nome della classe separando namespace dal nome "proprio" della classe stessa. Unica cosa degna di nota, viene eliminato il primo ramo del namespace, che solitamente è il nome del progetto. new \ProjectName\Core\Othernamespace\Classname()Causerà una include automatica del percorso
Core/Othernamespace/Classname.php
[mysqld] log-bin=mysql-bin server-id=1Il parametro server-id può essere un numero qualsiasi tra 1 e (232-1) e deve essere univoco tra i vari server MySql della rete Master Slave che si vuole creare. Il mio consiglio è quello di andare in ordine crescente: 1 per il master, dal 2 in poi per gli slave.
mysqldump -h master_host -u root - p --all-databases --master-data -e > dump.sqlIl comando eseguirà il dump creando il file dump.sql. Apriamo a questo punto il file con un editor di testi e segnamoci, da una parte, i comandi relativi al master_log_file e master_log_pos. Ad esempio, nel mio caso:
MASTER_LOG_FILE='mysql-bin.000016', MASTER_LOG_POS=458850265;Come ho scritto, segnamo a parte le informazioni relative al log file e alla posizione del log. La posizione del log indicherà allo slave la posizione di partenza del dump importato.
CREATE USER 'repl'@'%' IDENTIFIED BY 'slavepass'; GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
[mysqld] server-id=2o comunque un numero diverso da altri server Mysql e soprattutto differente dall'id del master. Riavviare il servizio MySql del server slave.
mysql -h slave_host -u root -p < dump.sqlEd attendere il completamento dell'operazione.
CHANGE MASTER TO MASTER_HOST='master_host', MASTER_USER='repl', MASTER_PASSWORD='slavepass', MASTER_LOG_FILE='mysql-bin.000016', MASTER_LOG_POS=458850265
START SLAVE;si iniziano le danze. E' possibile a questo punto controllare lo stato della replicazione eseguendo sul server slave
SHOW SLAVE STATUS;
GPIO di un Raspberry Pi (http://www.raspberrypi.org),
suonare musica, interrogare API pubbliche meteo, leggere email, connettersi a facebook e leggere le notifiche, e così via.
bower install summernote
<link href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.min.css" rel="stylesheet"></link> <!-- include summernote css/js--> <link href="summernote.css" rel="stylesheet"></link> <script src="summernote.min.js"></script>
<div id="summernote">Hello Summernote</div>
<script>
$(document).ready(function() {
$('#summernote').summernote();
});
</script>
<?php
//Tradotto in php dall'originale
//http://stackoverflow.com/questions/7490660/converting-wind-direction-in-angles-to-text-words
function degToCompass($num) {
$val=floor(($num/22.5)+.5);
$arr=["N","NNE","NE","ENE","E","ESE", "SE", "SSE","S","SSW","SW","WSW","W","WNW","NW","NNW"];
return $arr[($val % 16)];
}
$condizioni = array(
"0"=> "tornado",
"1"=> "tempesta tropicale",
"2"=> "uragano",
"3"=> "forti temporali",
"4"=> "temporali",
"5"=> "pioggia mista a neve",
"6"=> "pioggia mista a nevischio",
"7"=> "neve mista a nevischio",
"8"=> "pioviggine gelata",
"9"=> "pioggerella",
"10"=> "pioggia gelata",
"11"=> "rovesci",
"12"=> "rovesci",
"13"=> "raffiche di neve",
"14"=> "rovesci di neve leggeri",
"15"=> "soffia neve",
"16"=> "neve",
"17"=> "grandinare",
"18"=> "nevischio",
"19"=> "polvere",
"20"=> "nebbioso",
"21"=> "foschia",
"22"=> "foschia",
"23"=> "ventoso",
"24"=> "ventoso",
"25"=> "freddo",
"26"=> "nuvoloso",
"27"=> "Sereno",
"28"=> "Sereno",
"29"=> "parzialmente nuvoloso",
"30"=> "parzialmente nuvoloso",
"31"=> "Sereno",
"32"=> "soleggiato",
"33"=> "Sereno",
"34"=> "Sereno",
"35"=> "pioggia mista e grandine",
"36"=> "caldo",
"37"=> "isolati temporali",
"38"=> "temporali sparsi",
"39"=> "temporali sparsi",
"40"=> "Rovesci sparsi",
"41"=> "tormenta di neve",
"42"=> "rovesci di neve sparsi",
"43"=> "tormenta di neve",
"44"=> "parzialmente nuvoloso",
"45"=> "rovesci temporaleschi",
"46"=> "rovesci di neve",
"47"=> "Temporali isolati",
"3200"=> "non disponibile"
);
$BASE_URL = "http://query.yahooapis.com/v1/public/yql";
$yql_query = 'select * from weather.forecast where woeid in (select woeid from geo.places(1) where text="Rimini, Italy") and u="c"';
$yql_query_url = $BASE_URL . "?q=" . urlencode($yql_query) . "&format=json";
$session = curl_init($yql_query_url);
curl_setopt($session, CURLOPT_RETURNTRANSFER,true);
$json = curl_exec($session);
$phpObj = json_decode($json);
echo "\nMeteo per Rimini\n";
echo "----------------\n";
echo "Temperatura: ";
echo $phpObj->query->results->channel->item->condition->temp."° C\n";
echo "Condizioni meteo: ";
echo $condizioni[$phpObj->query->results->channel->item->condition->code]."\n";
echo "Alba: ";
echo $phpObj->query->results->channel->astronomy->sunrise."\n";
echo "Tramonto: ";
echo $phpObj->query->results->channel->astronomy->sunset."\n";
echo "Umidità: ";
echo $phpObj->query->results->channel->atmosphere->humidity."%\n";
echo "Pressione: ";
echo $phpObj->query->results->channel->atmosphere->pressure." millibar\n";
echo "Previsioni: ";
echo $condizioni[$phpObj->query->results->channel->item->forecast[0]->code];
echo ", t. max ".$phpObj->query->results->channel->item->forecast[0]->high;
echo "° C, t. min ".$phpObj->query->results->channel->item->forecast[0]->low." °C \n";
echo "Vento: ";
echo $phpObj->query->results->channel->wind->speed." km/h ";
echo degToCompass($phpObj->query->results->channel->wind->direction)."\n";
root@CloudServer:~# parted
GNU Parted 2.3
Using /dev/sda
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) print free
Model: VMware Virtual disk (scsi)
Disk /dev/sda: 32.2GB
Sector size (logical/physical): 512B/512B
Partition Table: msdos
Number Start End Size Type File system Flags
32.3kB 1049kB 1016kB Free Space
1 1049kB 256MB 255MB primary ext2 boot
256MB 257MB 1048kB Free Space
2 257MB 10.7GB 10.5GB extended
5 257MB 10.7GB 10.5GB logical lvm
10.7GB 32.2GB 21.5GB Free Space
2. creare una nuova partizione con il comandoroot@CloudServer:~# cfdiskselezionare la riga dello spazio libero interessato, selezionare New, poi scegliere partizione Logica [Edit: un utente mi ha giustamente fatto notare che a questo punto, è necessario specificarne il formato, ossia 8E]. Infine selezionare Write per salvare le modifiche e infine Quit per uscire. Nel mio caso è stato necessario riavviare la macchina virtuale, quindi consiglio di farlo.
root@CloudServer:~# fdisk -l /dev/sda Disk /dev/sda: 32.2 GB, 32212254720 bytes 255 heads, 63 sectors/track, 3916 cylinders, total 62914560 sectors Units = sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disk identifier: 0x000bc621 Device Boot Start End Blocks Id System /dev/sda1 * 2048 499711 248832 83 Linux /dev/sda2 501758 62914559 31206401 5 Extended /dev/sda5 501760 20969471 10233856 8e Linux LVM /dev/sda6 20969535 62914559 20972512+ 83 Linux
root@CloudServer:~# pvcreate /dev/sda6 Physical volume "/dev/sda6" successfully created
root@CloudServer:~# pvdisplay --- Physical volume --- PV Name /dev/sda5 VG Name vg PV Size 9.76 GiB / not usable 2.00 MiB Allocatable yes (but full) PE Size 4.00 MiB Total PE 2498 Free PE 0 Allocated PE 2498 PV UUID 5fDfUK-6RjG-nFMX-iNgM-44rF-7zz0-4JIr9Y "/dev/sda6" is a new physical volume of "20.00 GiB" --- NEW Physical volume --- PV Name /dev/sda6 VG Name PV Size 20.00 GiB Allocatable NO PE Size 0 Total PE 0 Free PE 0 Allocated PE 0 PV UUID hu4B6U-WDfx-zocW-13uX-BiwJ-2CoM-LHKhT9
root@CloudServer:~# vgextend vg /dev/sda6 Volume group "vg" successfully extended
root@CloudServer:~# lvdisplay --- Logical volume --- LV Path /dev/vg/lv_swap LV Name lv_swap VG Name vg LV UUID CohmrO-3wcX-zLMV-exxT-gUDu-dAxo-vJhfD4 LV Write Access read/write LV Creation host, time ubuntu, 2014-07-18 10:33:32 +0200 LV Status available # open 2 LV Size 952.00 MiB Current LE 238 Segments 1 Allocation inherit Read ahead sectors auto - currently set to 256 Block device 252:0 --- Logical volume --- LV Path /dev/vg/lv_root LV Name lv_root VG Name vg LV UUID VxYaWt-nPDZ-zTos-Bhbk-0dyz-vlX4-5P06Qc LV Write Access read/write LV Creation host, time ubuntu, 2014-07-18 10:33:44 +0200 LV Status available # open 1 LV Size 8.83 GiB Current LE 2260 Segments 1 Allocation inherit Read ahead sectors auto - currently set to 256 Block device 252:1
root@CloudServer:~# lvextend -l+100%FREE /dev/vg/lv_root Extending logical volume lv_root to 28.82 GiB Logical volume lv_root successfully resized
root@CloudServer:~# resize2fs /dev/mapper/vg-lv_root resize2fs 1.42.9 (4-Feb-2014) Filesystem at /dev/mapper/vg-lv_root is mounted on /; on-line resizing required old_desc_blocks = 1, new_desc_blocks = 2 The filesystem on /dev/mapper/vg-lv_root is now 7556096 blocks long.
root@CloudServer:~# df -h Filesystem Size Used Avail Use% Mounted on /dev/mapper/vg-lv_root 29G 1.7G 26G 6% / none 4.0K 0 4.0K 0% /sys/fs/cgroup udev 991M 4.0K 991M 1% /dev tmpfs 201M 532K 200M 1% /run none 5.0M 0 5.0M 0% /run/lock none 1002M 0 1002M 0% /run/shm none 100M 0 100M 0% /run/user /dev/sda1 236M 39M 185M 18% /boot
$('body').append($('<div></div>').load('file_esterno.html', function() {
//Qui operazioni opzionali sull'html appena caricato
});
:-)
<div id="mappamondo-richieste" style="height:350px;width:100%;"></div>
$.ajax({
type: "GET",
url: 'http://api.example.com/stats/world/',
dataType: "json",
}).done(function( json_response ) {
$('#mappamondo-richieste').vectorMap({
map: 'world_mill_en',
series: {
regions: [{
values: json_response.worldData,
scale: ['#C8EEFF', '#0071A4'],
normalizeFunction: 'polynomial'
}]
},
onRegionLabelShow: function(e, el, code){
if(!json_response.worldData[code]) json_response.worldData[code] = 0;
el.html(el.html()+' ('+json_response.worldData[code]+')');
}
});
}).fail(function(jqXHR, textStatus) {
console.log( "Request failed: " + textStatus + " " + jqXHR.status );
});
{
"worldData":
{
"IT":"97",
"US":"357"
}
}
Il risultato finale non delude le mie aspettative :-)RawPrinterHelper.SendStringToPrinter("Zebra GX420T", "^XA^FDESEMPIO^FS^XZ");
Di seguito posto anche il codice originale della classe, che si può trovare comunque a questo indirizzo: http://support.microsoft.com/kb/322091/it
using System;
using System.Drawing;
using System.Drawing.Printing;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.IO;
namespace TintoLavaApp
{
public class RawPrinterHelper
{
// Structure and API declarions:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class DOCINFOA
{
[MarshalAs(UnmanagedType.LPStr)]
public string pDocName;
[MarshalAs(UnmanagedType.LPStr)]
public string pOutputFile;
[MarshalAs(UnmanagedType.LPStr)]
public string pDataType;
}
[DllImport("winspool.Drv", EntryPoint = "OpenPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPStr)] string szPrinter, out IntPtr hPrinter, IntPtr pd);
[DllImport("winspool.Drv", EntryPoint = "ClosePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool ClosePrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint = "StartDocPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool StartDocPrinter(IntPtr hPrinter, Int32 level, [In, MarshalAs(UnmanagedType.LPStruct)] DOCINFOA di);
[DllImport("winspool.Drv", EntryPoint = "EndDocPrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool EndDocPrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint = "StartPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool StartPagePrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint = "EndPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool EndPagePrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint = "WritePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool WritePrinter(IntPtr hPrinter, IntPtr pBytes, Int32 dwCount, out Int32 dwWritten);
// SendBytesToPrinter()
// When the function is given a printer name and an unmanaged array
// of bytes, the function sends those bytes to the print queue.
// Returns true on success, false on failure.
public static bool SendBytesToPrinter(string szPrinterName, IntPtr pBytes, Int32 dwCount)
{
Int32 dwError = 0, dwWritten = 0;
IntPtr hPrinter = new IntPtr(0);
DOCINFOA di = new DOCINFOA();
bool bSuccess = false; // Assume failure unless you specifically succeed.
di.pDocName = "My C#.NET RAW Document";
di.pDataType = "RAW";
// Open the printer.
if (OpenPrinter(szPrinterName.Normalize(), out hPrinter, IntPtr.Zero))
{
// Start a document.
if (StartDocPrinter(hPrinter, 1, di))
{
// Start a page.
if (StartPagePrinter(hPrinter))
{
// Write your bytes.
bSuccess = WritePrinter(hPrinter, pBytes, dwCount, out dwWritten);
EndPagePrinter(hPrinter);
}
EndDocPrinter(hPrinter);
}
ClosePrinter(hPrinter);
}
// If you did not succeed, GetLastError may give more information
// about why not.
if (bSuccess == false)
{
dwError = Marshal.GetLastWin32Error();
}
return bSuccess;
}
public static bool SendFileToPrinter(string szPrinterName, string szFileName)
{
// Open the file.
FileStream fs = new FileStream(szFileName, FileMode.Open);
// Create a BinaryReader on the file.
BinaryReader br = new BinaryReader(fs);
// Dim an array of bytes big enough to hold the file's contents.
Byte[] bytes = new Byte[fs.Length];
bool bSuccess = false;
// Your unmanaged pointer.
IntPtr pUnmanagedBytes = new IntPtr(0);
int nLength;
nLength = Convert.ToInt32(fs.Length);
// Read the contents of the file into the array.
bytes = br.ReadBytes(nLength);
// Allocate some unmanaged memory for those bytes.
pUnmanagedBytes = Marshal.AllocCoTaskMem(nLength);
// Copy the managed byte array into the unmanaged array.
Marshal.Copy(bytes, 0, pUnmanagedBytes, nLength);
// Send the unmanaged bytes to the printer.
bSuccess = SendBytesToPrinter(szPrinterName, pUnmanagedBytes, nLength);
// Free the unmanaged memory that you allocated earlier.
Marshal.FreeCoTaskMem(pUnmanagedBytes);
return bSuccess;
}
public static bool SendStringToPrinter(string szPrinterName, string szString)
{
IntPtr pBytes;
Int32 dwCount;
// How many characters are in the string?
dwCount = szString.Length;
// Assume that the printer is expecting ANSI text, and then convert
// the string to ANSI text.
pBytes = Marshal.StringToCoTaskMemAnsi(szString);
// Send the converted ANSI string to the printer.
SendBytesToPrinter(szPrinterName, pBytes, dwCount);
Marshal.FreeCoTaskMem(pBytes);
return true;
}
}
}
try
{
txt_esempio.Invoke((MethodInvoker)delegate() {
txt_esempio.Text = "Testo modificato da backgroundWorker";
});
}
catch (InvalidOperationException ioe) { }
$config['image_library'] = 'gd2';
$config['source_image'] = '/percorso/mypic.jpg';
$config['maintain_ratio'] = TRUE;
$config['width'] = 75;
$config['height'] = 50;
//Carico la libreria con la configurazione
$this->load->library('image_lib', $config);
//Ridimensiono l'immagine /percorso/mypic.jpg
$this->image_lib->resize();
$config['new_image'] = '/percorso/nuovaimmaginediversa.jpg';
$config['image_library'] = 'gd2';
$config['source_image'] = '/percorso/mypic.jpg';
$config['rotation_angle'] = 'hor';
//Carico la libreria con la configurazione
$this->load->library('image_lib', $config);
$this->image_lib->rotate();
$config['image_library'] = 'gd2';
$config['source_image'] = '/percorso/mypic.jpg';
$config['x_axis'] = '100';
$config['y_axis'] = '60';
//Carico la libreria con la configurazione
$this->load->library('image_lib', $config);
//Eseguo il cropping
$this->image_lib->crop();
$config['image_library'] = 'gd2';
$config['source_image'] = '/percorso/mypic.jpg';
$config['wm_vrt_alignment'] = 'bottom';
$config['wm_hor_alignment'] = 'right';
$config['wm_padding'] = '5';
$config['wm_overlay_path'] = '/percorso/watermark.png';
//Carico la libreria con la configurazione
$this->load->library('image_lib', $config);
//Eseguo l'aggiunta del watermark
$this->image_lib->watermark();
//Impostazioni cropping
$config['image_library'] = 'gd2';
$config['source_image'] = '/percorso/mypic.jpg';
$config['x_axis'] = '100';
$config['y_axis'] = '60';
//Carico la libreria con la configurazione
$this->load->library('image_lib', $config);
//Eseguo il cropping
$this->image_lib->crop();
//Cancello le impostazioni della libreria
$this->image_lib->clear();
//Impostazioni per rotazione orizzontale
$config['image_library'] = 'gd2';
$config['source_image'] = '/percorso/mypic.jpg';
$config['rotation_angle'] = 'hor';
//Carico la libreria con la configurazione
$this->image_lib->initialize($config);
//Eseguo la rotazione
$this->image_lib->rotate();
application/libraries/Format.php application/libraries/REST_Controller.php application/config/rest.phpnella propria directory application, e ricordarsi di caricare automaticamente la classe REST_Controller come libreria nel fi le di con gurazione
application/config/autoload.phpPer personalizzare le opzioni di restserver, basta modi care l'apposito fi le precedentemente copiato:
application/config/rest.php
class News extends REST_Controller
{
public function index_get()
{
// Lettura delle news
}
public function index_post()
{
// Crea una news
}
public function index_put()
{
// Modifica una news
}
public function index_delete()
{
// Elimina una news
}
}
Una richiesta del tipo
GET http://www.example.com/newscomporterà l'esecuzione della funzione index_get, index perché l'url è senza una funzione specificata (news è direttamente il controller) e get perché il metodo HTTP utilizzato è, appunto, GET.
$this->get('id'); //mappatura di $this->input->get()
$this->post('id'); //mappatura di $this->input->post()
$this->put('id');
Per i parametri del metodo DELETE, poiché lo standard non li prevede, è sufficiente gestirli direttamente dalla funzione richiamata dal controllore:
public function index_delete($id)
{
$this->response(array(
'returned from delete:' => $id,
));
}
public function index_post()
{
// ...crea una news
$this->response($news, 201); // Manda la risposta HTTP 201
}
Queste sono i tips principali per lo sviluppo di un sistema API con codeigniter-restserver. Non ho parlato per motivi di tempo delle altre caratteristiche della libreria, quali la gestione di API Keys, la gestione dell'autenticazione ecc. per le quali rimando direttamente al sito ufficiale.
application
|- controllers
|- api
|- news.php
http://www.example.com/api/news/getAll http://www.example.com/api/news/getSingle/12richiedendo l'esecuzione del controller news.php che compare nell'albero di esempio, con i metodi getAll senza parametri e getSingle con un parametro GET valorizzato a "12".
class News extends CI_Controller {
public function getAll()
{
$query = $this->db->get('news');
$elenco_news = array();
foreach ($query->result() as $row)
{
$news = new stdClass();
$news->id = $row->id;
$news->titolo = $row->titolo;
$news->contenuto = $row->contenuto;
array_push($elenco_news, $news);
}
echo json_encode($elenco_news);
}
public function getSingle(id)
{
$this->db->from('news')->where('id',$id);
$query = $this->db->get();
$row = $query->row();
$news = new stdClass();
$news->id = $row->id;
$news->titolo = $row->titolo;
$news->contenuto = $row->contenuto;
echo json_encode($news);
}
}
Sarà sufficiente quindi creare un controller per ogni tipo di risorsa (ad esempio news, eventi, banner) ed i relativi metodi, ricordandosi di strutturare le risposte in formato JSON come da esempio.
funzionecallback({"status":"ok"})
Mentre il rispettivo JSON sarebbe{"status":"ok"}
La funzione di callback lato client si può specificare mediante un apposito comando di configurazione di $.ajax oppure lasciare che sia jQuery a decidere il nome della callback ed a inviarlo come parametro GET (chiamato appunto, callback) alle API.$obj = new stdClass();
$obj->id = "56321564";
$obj->descrizione = "Prova di descrizione";
if ($_GET['callback']!='') {
echo $_GET['callback'].'('.json_encode($obj).')';
}
else {
echo json_encode($obj);
}
In questo modo siamo in grado di capire in maniera molto semplice (senza header http) in che formato mostrare il risultato: se esiste un parametro GET chiamato callback, lo script deve utilizzare il formato JSONP, altrimenti il JSON normale.
var apiUrl = "http://www.example.com/api/example.php";
$( document ).ready(function() {
$.ajax({
type: "GET",
url: apiUrl,
dataType: "jsonp" ,
crossDomain: true,
}).done(function( json_response ) {
console.log(JSON.stringify(json_response));
}).fail(function(jqXHR, textStatus) {
$('#result').html( "Request failed: " + textStatus + " " + jqXHR.status );
});
});
La quale produrrà il risultato voluto in console:
{"id":"56321564", "descrizione": "Prova di descrizione"}
Importanti sono l'opzione dataType nella chiamata Ajax impostata su jsonp e crossDomain impostato su true.
sudo apt-get install lighttpd sudo apt-get install php5-common php5-cgi php5 sudo lighty-enable-mod fastcgi-php sudo service lighttpd force-reload sudo chown www-data:www-data /var/www sudo chmod 775 /var/www sudo apt-get install espeakFacciamo una prova, poi eseguiamo visudo per dare i diritti di esecuzione all'utente www-data attraverso visudo
espeak -vit "Prova di testing" sudo visudoLo so che è un incredibile errore di sicurezza, ma tanto il mio RaspberryPi sta solo in casa e quindi per facilità ho abilitato l'utente a poter eseguire con sudo e senza password qualsiasi comando. Aggiungiamo quindi la seguente riga nel visudo
www-data ALL=(ALL) NOPASSWD: ALLCreiamo una pagina php sotto la cartella /var/www con il seguente contenuto:
<?php
echo exec(" sudo /usr/bin/espeak -vit \"Questo messaggio viene riprodotto ogni volta che si visita la pagina da un browser\"", $out, $out2);
?>
Questo ovviamente apre uno scenario fantastico relativo alla domotica :-)