Mostrando entradas con la etiqueta PHP. Mostrar todas las entradas
Mostrando entradas con la etiqueta PHP. Mostrar todas las entradas

18 ene 2012

PHP y ORACLE

Ahora mismo estoy poniendo un producción un servidor en mi centro de trabajo, en el que además de tener que dar servicio para la base de datos PostgreSQL (explique hace poco cómo permitir conexiones entrantes a esta BBDD), debe hacer conexiones externas a una base de datos Oracle.
Estas conexiones las hará un script en PHP por lo que además, deberemos instalar OCI (Oracle Call Interface) para PHP. Suponemos que está ya instalado el servidor web Apache 2 y los componentes básicos de PHP.

Instalación de Oracle instantclient
Antes de instalar el instantclient como tal, debemos instalar la librería libaio, necesaria para gestionar entradas/salidas asíncronas al kernel. La instrucción será (utilizo “#” en el prompt para indicar como superusuario, “$” en caso contrario):
# yum install libaio1
O si usamos una distribución que use APT:
# apt-get install libaio1
Lo siguiente será acceder al portal de descargas de Oracle y descargar los componentes necesarios para el instantclient:
  • Basic
  • Devel
  • SQLPlus
Elegimos la última versión, nuestra arquitectura  y descargamos los paquetes RPM. La instalación será inmediata si tenemos una distribución basada en Red Hat:
# yum install paquete.rpm
En caso contrario, deberemos instalar alien previamente para que convierta los paquetes RPM en paquetes DEB:
# apt-get install alien
# alien paquete.rpm
# dpkg -i paquete.deb
Ahora ya nos tocar configurar el famoso fichero Tnsnames.ora. Este fichero variará de una configuración a otra por lo que sólo vamos a comentar dónde situarlo. Su ruta debe ser: /etc/oracle/tnsnames.ora, en caso de no existir, deberemos crearla.
Para terminar, deberemos crear unas variables de entorno. Para ello accedemos al fichero /root/.bashrc como superusuario e incluimos las siguientes líneas:
export TNS_ADMIN=/etc/oracleexport SQLPATH=/usr/lib/oracle/11.1.0.1/client/binexport LD_LIBRARY_PATH=/usr/lib/oracle/11.1.0.1/client/lib:$LD_LIBRARY_PATHexport PATH=$PATH:$SQLPATH
En algunas distribuciones, también podréis hacer ese cambio en otro fichero: /etc/environment.

Instalación de OCI en PHP
Ahora nos toca la parte de PHP, es decir, instalar los componentes necesarios para poder hacer llamadas a Oracle desde PHP usando el instantclient que acabamos de instalar (con lo fácil que es hacer esto mismo con MySQL o PostgreSQL…, las cosas del software cerrado).
Suponemos que tenemos instalado Apache2 y PHP, pero aún así instalaremos dos paquetes más:
# yum install php-pear php5-dev
# apt-get install php-pear php5-dev
PHP-PEAR es según definen sus siglas: PHP Extension and Application Repository, es decir, un repositorio de extensiones y aplicaciones para PHP que nos permite instalar sin problemas ciertos componentes de PHP que no podemos instalar a través de nuestro gestor de paquetes habitual (me recuerda a CPAN con Perl, pero esa es otra historia para otra entrada).

Ya estamos en disposición de ejecutarlo para instalar OCI:
pecl install oci8
En la terminal nos aparecerá algo así como:
1-1, ‘all’, ‘abort’, or Enter to continue:
Pulsamos “1″ luego ENTER y escribimos las siguientes opciones (debemos saber el PATH exacto de nuestras librerías Oracle, cambiará en función de la versión):
shared,instantclient,/usr/lib/oracle/mi_version/client/lib/
PHP-PEAR descargará, configurará, compilará e instalará el módulo. Finalmente, tenemos que añadir a nuestro fichero php.ini una línea para que cargue la librería dinámica de OCI y puedan hacerse llamadas desde los ficheros PHP.
La ruta del fichero será: /etc/php5/apache2/php.ini y la línea a agregar junto a las demás extensiones la siguiente:
extension=oci8.so
Reiniciamos el servidor web y listo:
services httpd restart
O:
/etc/init.d/apache2 reload

3 jun 2011

PHP date difference

Step 1 - PHP date difference


PHP date difference
If you want to get the difference between to dates or time values, then you first need to get the values in the same format. The best way is to convert both dates into Unix timestamp format. In this case the date and time information is stored as an integer so we can calculate the difference easily. You can get the Unix timestamp in various ways as you can see below:
Code:
  1. // Get current time
  2. $date1 = time();
  3. // Get the timestamp of 2006 October 20
  4. $date2 = mktime(0,0,0,10,20,2006);
  5. ?>
Now as you have the values getting the difference is quite easy. However the result will be an integer value, but you probably want to get it in days, hours and minutes. To do so we need to convert back our int value into a usable date format. We know that the difference is in seconds so we can get how many full days it is. To get it we use the following code:
Code:
  1. $dateDiff = $date1 - $date2;
  2. $fullDays = floor($dateDiff/(60*60*24));
  3. echo "Differernce is $fullDays days";
  4. ?>
We used the floor function as we want to get only the complete days. Besides this the 60*60*24 represents that a day has 24 ours and each hour has 60 minutes and each minute has 60 seconds.
As next step we need to get how many hours are still present in the remaining seconds. So from the original difference we need to remove the complete days in seconds and from the remaining value we can calculate the full hours similar to as we calculated the full days. Repeating these steps for minutes as well at the end we get the difference between the original dates. The complete calculation looks like this:
Code:
  1. $dateDiff = $date1 - $date2;
  2. $fullDays = floor($dateDiff/(60*60*24));
  3. $fullHours = floor(($dateDiff-($fullDays*60*60*24))/(60*60));
  4. $fullMinutes = floor(($dateDiff-($fullDays*60*60*24)-($fullHours*60*60))/60);
  5. echo "Differernce is $fullDays days, $fullHours hours and $fullMinutes minutes.";
  6. ?>

31 may 2011

PHP: Sorting Arrays - Manual

Sorting Arrays

PHP has several functions that deal with sorting arrays, and this document exists to help sort it all out.
The main differences are:
  • Some sort based on the array keys, whereas others by the values: $array['key'] = 'value';
  • Whether or not the correlation between the keys and values are maintained after the sort, which may mean the keys are reset numerically (0,1,2 ...)
  • The order of the sort: alphabetical, low to high (ascending), high to low (descending), numerical, natural, random, or user defined
  • Note: All of these sort functions act directly on the array variable itself, as opposed to returning a new sorted array
  • If any of these sort functions evaluates two members as equal then the order is undefined (the sorting is not stable).
Sorting function attributes
Function name Sorts by Maintains key association Order of sort Related functions
array_multisort() value associative yes, numeric no first array or sort options array_walk()
asort() value yes low to high arsort()
arsort() value yes high to low asort()
krsort() key yes high to low ksort()
ksort() key yes low to high asort()
natcasesort() value yes natural, case insensitive natsort()
natsort() value yes natural natcasesort()
rsort() value no high to low sort()
shuffle() value no random array_rand()
sort() value no low to high rsort()
uasort() value yes user defined uksort()
uksort() key yes user defined uasort()
usort() value no user defined uasort()

10 may 2011

CCK Overview and Structure | drupal.org

CCK Overview and Structure

Overview

CCK is comprised of 2 things:
  • fields: These refer to the data that's being stored. For example, Text or Number.
  • widgets: These refer to how the input widget an end user uses to enter the data looks. For example, Text field or Check boxes.

Data Model

CCK Data Model
CCK's data model consists of 3 base tables:
  • node_type_content: A table containing the CCK node type defninitions: name, label, description, help, and the label given to the node's Title field.
  • node_field: A table containing the various field definitions: field name, type, and various settings.
  • node_field_instance: An individual instance of a field applied to a content type, along with its widget settings. For example, field_description in the content_blog type and field_description in the content_product type.
In addition, each new content type creates its own table, called node_content_X, where X is the name of the content type. This table contains a node ID (nid) and revision ID (vid) field, along with the values of any extra fields, if the field is specific to that content type.
If, however, a field is shared among more than one content type, a table called node_data_field_X, where X is the name of the field, is also created to track the field's settings between node types.

Hooks

Note: More detailed hook information is available from the file field.php in the CCK module.

Fields

  • hook_field_info(): Here you declare the label for your field type(s). This will show up when you click "add field" on a CCK content type.
  • hook_field_settings($op, $field): Handles displaying, validating, and saving field settings forms. In addition, manages how they're stored in the database and provides Views integration.
  • hook_field($op, &$node, $field, &$node_field, $teaser, $page): Define the behavior of a field type.
  • hook_field_formatter_info(): Declare information about a formatter.
  • hook_field_formatter($field, $item, $formatter, $node): Prepare an individual item for viewing in a browser.

Widgets

  • hook_widget_info(): Here you declare any widgets associated with your field type. These will show up below the fields when you click "add field" on a CCK content type in 4.7.x and 5.x. Fields show up in the first drop-down and widgets in the second drop down when adding content types in 6.x.
  • hook_widget_settings($op, $widget): Handle the parameters for a widget.
  • hook_widget: Define the behavior of a widget.

Tips

  • While developing CCK, you may notice oddities such as settings you made not appearing and other such things. Always remember to clear your cache!

Comments

Thanks for this valuable overview!
If, however, a field is shared among more than one content type, a table called node_data_field_X, where X is the name of the field, is also created
The node_data_field_X table is also created when the field is of type "Multiple values". This happens even if the field is not shared among content types.
When the field is multiple-valued, the node_data_field_X table contains an additional column: delta.

I think you have an error in the diagram for the node_data_field_X table. The picture shows two fields in that table: field1 and field2. However, one node_data_field_X table holds data for one field only, so you need to remove "field2" from this table. (And, you must rename the remaining "field1" to "field3", or whatever, because "field1" already exists in node_content_X.)
(BTW, what software did you use to create this beautiful diagram?)

(You should add the _value suffix to the appropriate column names in your diagram.)
Have you ever wondered about the "_value" suffix in column names?
A field's data may actually occupy more than one DB column. It's true that the simple Text and Number fields occupy only one column (field_X_value), but the more complex Date field, for example, occupies two DB columns: field_X_value and field_X_timezone.
There's nothing "holy" in a _value suffix:
Let's say I want to create a new field type: Color. This field will occupy three DB columns (for the red, green and blue intensities). I'll define my hook_field_settings as:
function color_field_settings($op, ...) {
switch(
$op) {
...
case
'database columns':
return array(
'red' => array('type' => 'integer', ...),
'green' => array('type' => 'integer', ...),
'blue' => array('type' => 'integer', ...)
);
...
}
}
?>
Now, if I add such field, let's call it "favorite color", to my content type, my content type table would contain three new columns: field_favorite_color_red, field_favorite_color_blue and field_favorite_color_green. It would not contain field_favorite_color_value, because such a column ("value") was not defined in color_field_settings.
Similarly, the nodereference field doesn't define a "value" column. It defines "nid" instead:
function nodereference_field_settings($op, $field) {
switch(
$op) {
...
case
'database columns':
$columns = array(
'nid' => array('type' => 'int', 'not null' => TRUE, 'default' => '0'),
);
return
$columns;
...
}
}
?>
A "value" column is defined in number_field_settings and text_field_settings.
BTW, contrary to what I've said, the Text field is not so simple: it may occupy two DB columns if an input format may be applied to the string (that is, when the "Filtered text" option is selected).
(BTW #2, in my previous comment I said you should leave only one field (in CCK terms) in the diagram for the node_data_field_X table. But this one field may occupy several DB columns (depending on its type and settings)).

I wanted to convert some simple node types to cck to take advantage of the ability to add more fields to them. I had a couple custom types I created by copying the story.module that I wanted to convert, plus I wanted to make my basic event type into a cck event type and my basic og type into a cck type. I wanted to do all this without losing any of the data that existed. I thought I'd share the process and a php snippet that worked for me to do this. This should work for any simple content types (i.e. changing types that do not use revisions which only have a title and a body to a cck type with a single description field that will hold the body content).
  1. First, create the new cck content type you want to move to (in this example, it ended up named 'content_event')
  2. CCK doesn't use the body field, so you need to add a cck text field for the body content. Give the field more than 1 line to make it a textarea instead of a textfield, and be sure to indicate that it uses filtering. Note the name of the field that is created. For my example, I created a field called 'field_description'.
  3. Create a test node to be sure that everything got set up correctly and that you can manually enter data into your new content type and that it gets saved correctly. Be sure that you get a textarea field instead of a textfield and that the filter is available for selection.
  4. Make a good backup of your database. Go ahead and make another one just in case :-)
  5. Now run the following code to change the data in the database.
Note: I can see that the code gets cut off when posted. I tried several methods of posting it and none displayed correctly, so if it's getting cut off, just pick it up from the source of this page.
// convert another node type to a cck type
$from_type = 'event';
$to_type = 'content_event';

// the name of the cck field that will hold the value of the node body
$to_body_field = 'field_description';

// pull up nodes with the old content type
$results = db_query("SELECT nid, title FROM node where type='$from_type' ORDER BY nid");
while ($arr = db_fetch_array($results)) {
$nid = $arr['nid'];

drupal_set_message('Converting '.$arr['nid'].': '.$arr['title']);

// create a cck record for this node and make sure it's not a duplicate
db_query("DELETE FROM node_".$to_type." WHERE nid=$nid");
db_query("INSERT INTO node_".$to_type." SET nid=$nid, vid=$nid");

// change the node type in the node table
db_query("UPDATE node SET type='$to_type' WHERE nid=$nid");
// move the value in node body to the cck body field
if ($to_body_field) {
$node = node_load($nid);
$results2 = db_query("SELECT format, body FROM node_revisions WHERE nid=$nid");
while ($arr2 = db_fetch_array($results2)) {
// if there is a body value save it to new field
if ($arr2['body'] > '') {
$node->$to_body_field = array(
0 => array(
'value' => $arr2['body'],
'format' => $arr2['format'],
),
);
node_save($node);
$node = node_load($nid);
$value = $node->$to_body_field;
if ($value[0]['value'] == $arr2['body'] && $value[0]['value'] > '') {
// if successful, erase the body and teaser (cck doesn't use them)
db_query("UPDATE node_revisions SET body='', teaser='' WHERE nid=$nid");
}
}
}
}
}
// update other tables that use content type name
db_query("UPDATE vocabulary_node_types SET type='$to_type' WHERE type='$from_type'");

$node->$to_body_field = array(
0 => array(
'value' => $arr2['body'],
'format' => $arr2['format'],
),
);
I wondered a lot where to find out what the fields actually looked like, and how to set the fields of a CCK node from php like this, but then I installed the devel module, which lets you see the Object Structure of each node you create, making it easy to just create a node and then see what the arrays in the field_foobar's look like.

multiple values?

Can someone with more intimite knowledge of CCK shine some light on this 'multiple' thing?
* why is it there?
* what is it for?
* how should developers handle this when storing their own data in private tables?
---
Professional | Personal
| Sympal: Development and Hosting

This has been confusing many people and I'm not sure exactly what the original intention was. The clearest use case is when it is combined with optionwidgets or nodereference or userreference where it makes it possible to select and store multiple values in your selectors. It gets murky beyond that because it creates an undefined number of additional instances of whatever field you use it with, but with no ability to give those additional instances their own name or identifier (or even to specify how many of them you want). So you can use a text field to store phone numbers and store 2 different phone numbers by using the multiple option, but you won't be able to give them labels to identify which is which. You could also store multiple images with imagefield or multiple files with filefield, which might be more useful. I was also playing with the idea of storing multiple date fields in a single event node as a way to handle repeating events without creating duplicate nodes which might be another legitimate way to use this capability.

Multiple makes sense if you want multiple values of the same type. A book may have one author or many. You want the Author field to change from a single string to multiple strings.
What would be of use are examples of more complex relationships.
Similar fields with different means should be processed some other way and I am still looking for an example built with CCK. Suppose I have a Contact node and add a telephone field. I then want to have home and work numbers. I could change telephone to have multiple but that does not let me find out which is the work number. I could define separate fields named work_telephone and home_telephone but then I have to define the same format twice. It makes sense to define telephone then telephone.work and telephone.home to inherit telephone's attributes. I think that is where widgets are used. You define a widget to handle the telephone format then apply the one widget to both telephone fields.
What makes sense next, and again I have not found a current example implemented with CCK, is to have minimum and maximum entries in multiple. You might have a field xyz that has to have a minimum of two entries or a maximum of 10 entires. I am thinking of polls where you ask people to nominate their top 10 choices or emergency contact details where you might ask someone to nominate a minimum of two forms of contact.
Perhaps we could start pages in the CCK documentation with the questions and leave space for more experienced users to add the answers.
petermoulding.com/web_architect

The multiple values I've found very useful, and I've used it in several places already.
An example in my case is "People attending Events":
Many people can attend an event, and many events can be attended by one person.
In the database, as mentioned before, a new table is created which has foreign keys for both person and event. This means the many-to-many relationship can exist without having to have a 'list' in a field (thus keeping it 3rd Normal Form).
What I'm saying is, the multiple values thing is essential (at least for me :)
Thanks for the documentation. I didn't realise this was here until now - figured it all out from poking around the database...

23 abr 2010

PHP: preg_match - Manual


Description

int preg_match ( string $pattern , string $subject [, array &$matches [, int $flags [, int $offset ]]] )

Searches subject for a match to the regular expression given in pattern.


Parameters

pattern

The pattern to search for, as a string.

subject

The input string.

matches

If matches is provided, then it is filled with the results of search. $matches[0] will contain the text that matched the full pattern, $matches[1] will have the text that matched the first captured parenthesized subpattern, and so on.

flags

flags can be the following flag:

PREG_OFFSET_CAPTURE
If this flag is passed, for every occurring match the appendant string offset will also be returned. Note that this changes the value of matches into an array where every element is an array consisting of the matched string at offset 0 and its string offset into subject at offset 1.
offset

Normally, the search starts from the beginning of the subject string. The optional parameter offset can be used to specify the alternate place from which to start the search (in bytes).

Note: Using offset is not equivalent to passing substr($subject, $offset) to preg_match() in place of the subject string, because pattern can contain assertions such as ^, $ or (?<=x). Compare:

= "abcdef";
$pattern = '/^def/';
preg_match($pattern, $subject, $matches, PREG_OFFSET_CAPTURE, 3);
print_r($matches);
?>

The above example will output:

Array
(
)

while this example

= "abcdef";
$pattern = '/^def/';
preg_match($pattern, substr($subject,3), $matches, PREG_OFFSET_CAPTURE);
print_r($matches);
?>

will produce

Array
(
[0] => Array
(
[0] => def
[1] => 0
)

)

Return Values

preg_match() returns the number of times pattern matches. That will be either 0 times (no match) or 1 time because preg_match() will stop searching after the first match. preg_match_all() on the contrary will continue until it reaches the end of subject. preg_match() returns FALSE if an error occurred.



Examples

Example #1 Find the string of text "php"

// The "i" after the pattern delimiter indicates a case-insensitive search
if (preg_match("/php/i", "PHP is the web scripting language of choice.")) {
echo
"A match was found.";
} else {
echo
"A match was not found.";
}
?>

Example #2 Find the word "web"

/* The \b in the pattern indicates a word boundary, so only the distinct
* word "web" is matched, and not a word partial like "webbing" or "cobweb" */
if (preg_match("/\bweb\b/i", "PHP is the web scripting language of choice.")) {
echo
"A match was found.";
} else {
echo
"A match was not found.";
}

if (
preg_match("/\bweb\b/i", "PHP is the website scripting language of choice.")) {
echo
"A match was found.";
} else {
echo
"A match was not found.";
}
?>

Example #3 Getting the domain name out of a URL

// get host name from URL
preg_match('@^(?:http://)?([^/]+)@i',
"http://www.php.net/index.html", $matches);
$host = $matches[1];

// get last two segments of host name
preg_match('/[^.]+\.[^.]+$/', $host, $matches);
echo
"domain name is: {$matches[0]}\n";
?>

The above example will output:

domain name is: php.net

Example #4 Using named subpattern

= 'foobar: 2008';

preg_match('/(?P\w+): (?P\d+)/', $str, $matches);

/* This also works in PHP 5.2.2 (PCRE 7.0) and later, however
* the above form is recommended for backwards compatibility */
// preg_match('/(?\w+): (?\d+)/', $str, $matches);

print_r($matches);

?>

The above example will output:

Array
(
[0] => foobar: 2008
[name] => foobar
[1] => foobar
[digit] => 2008
[2] => 2008
)

Tip

Do not use preg_match() if you only want to check if one string is contained in another string. Use strpos() or strstr() instead as they will be faster.