FINAL suepr merge step : added all modules to this super repos

This commit is contained in:
Bachir Soussi Chiadmi
2015-04-19 16:46:59 +02:00
7585 changed files with 1723356 additions and 18 deletions

View File

@@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

View File

@@ -0,0 +1,43 @@
Honeypot Module Readme
----------------------
Installation
------------
To install this module, place it in your sites/all/modules folder and enable it
on the modules page.
Configuration
-------------
All settings for this module are on the Honeypot configuration page, under the
Configuration section, in the Content authoring settings. You can visit the
configuration page directly at admin/config/content/honeypot.
Note that, when testing Honeypot on your website, make sure you're not logged in
as an administrative user or user 1; Honeypot allows administrative users to
bypass Honeypot protection, so by default, Honeypot will not be added to forms
accessed by site administrators.
Use in Your Own Forms
---------------------
If you want to add honeypot to your own forms, or to any form through your own
module's hook_form_alter's, you can simply place the following function call
inside your form builder function (or inside a hook_form_alter):
honeypot_add_form_protection($form, $form_state, array('honeypot', 'time_restriction'));
Note that you can enable or disable either the honeypot field, or the time
restriction on the form by including or not including the option in the array.
Credit
------
The Honeypot module was originally developed by Jeff Geerling of Midwestern Mac,
LLC (midwesternmac.com), and sponsored by flockNote (flocknote.com).

View File

@@ -0,0 +1,181 @@
<?php
/**
* @file
*
* Honeypot administration form.
*/
/**
* Honeypot administration page.
*/
function honeypot_admin_form($form, &$form_state) {
// Honeypot Configuration.
$form['configuration'] = array(
'#type' => 'fieldset',
'#title' => t('Honeypot Configuration'),
'#collapsible' => TRUE,
'#collapsed' => FALSE,
);
$form['configuration']['honeypot_protect_all_forms'] = array(
'#type' => 'checkbox',
'#title' => t('Protect all forms with Honeypot'),
'#description' => t('Enable Honeypot protection for ALL forms on this site (it is best to only enable Honeypot for the forms you need below).'),
'#default_value' => variable_get('honeypot_protect_all_forms', 0),
);
$form['configuration']['honeypot_protect_all_forms']['#description'] .= '<br />' . t('<strong>Page caching will be disabled on any page where a form is present if the Honeypot time limit is not set to 0.</strong>');
$form['configuration']['honeypot_log'] = array(
'#type' => 'checkbox',
'#title' => t('Log blocked form submissions'),
'#description' => t('Log submissions that are blocked due to Honeypot protection.'),
'#default_value' => variable_get('honeypot_log', 0),
);
$form['configuration']['honeypot_element_name'] = array(
'#type' => 'textfield',
'#title' => t('Honeypot element name'),
'#description' => t("The name of the Honeypot form field. It's usually most effective to use a generic name like email, homepage, or name, but this should be changed if it interferes with fields that are already in your forms. Must not contain spaces or special characters."),
'#default_value' => variable_get('honeypot_element_name', 'url'),
'#required' => TRUE,
'#size' => 30,
);
$form['configuration']['honeypot_time_limit'] = array(
'#type' => 'textfield',
'#title' => t('Honeypot time limit'),
'#description' => t('Minimum time required before form should be considered entered by a human instead of a bot. Set to 0 to disable.'),
'#default_value' => variable_get('honeypot_time_limit', 5),
'#required' => TRUE,
'#size' => 5,
'#field_suffix' => t('seconds'),
);
$form['configuration']['honeypot_time_limit']['#description'] .= '<br />' . t('<strong>Page caching will be disabled if there is a form protected by time limit on the page.</strong>');
// Honeypot Enabled forms.
$form['enabled_forms'] = array(
'#type' => 'fieldset',
'#title' => t('Honeypot Enabled Forms'),
'#description' => t("Check the boxes next to individual forms on which you'd like Honeypot protection enabled."),
'#collapsible' => TRUE,
'#collapsed' => FALSE,
'#states' => array(
// Hide this fieldset when all forms are protected.
'invisible' => array(
'input[name="honeypot_protect_all_forms"]' => array('checked' => TRUE),
),
),
);
// Generic forms.
$form['enabled_forms']['general_forms'] = array('#markup' => '<h5>' . t('General Forms') . '</h5>');
// User register form.
$form['enabled_forms']['honeypot_form_user_register_form'] = array(
'#type' => 'checkbox',
'#title' => t('User Registration form'),
'#default_value' => variable_get('honeypot_form_user_register_form', 0),
);
// User password form.
$form['enabled_forms']['honeypot_form_user_pass'] = array(
'#type' => 'checkbox',
'#title' => t('User Password Reset form'),
'#default_value' => variable_get('honeypot_form_user_pass', 0),
);
// If webform.module enabled, add webforms.
if (module_exists('webform')) {
$form['enabled_forms']['honeypot_form_webforms'] = array(
'#type' => 'checkbox',
'#title' => t('Webforms (all)'),
'#default_value' => variable_get('honeypot_form_webforms', 0),
);
}
// If contact.module enabled, add contact forms.
if (module_exists('contact')) {
$form['enabled_forms']['contact_forms'] = array('#markup' => '<h5>' . t('Contact Forms') . '</h5>');
// Sitewide contact form.
$form['enabled_forms']['honeypot_form_contact_site_form'] = array(
'#type' => 'checkbox',
'#title' => t('Sitewide Contact form'),
'#default_value' => variable_get('honeypot_form_contact_site_form', 0),
);
// Sitewide personal form.
$form['enabled_forms']['honeypot_form_contact_personal_form'] = array(
'#type' => 'checkbox',
'#title' => t('Personal Contact forms'),
'#default_value' => variable_get('honeypot_form_contact_personal_form', 0),
);
}
// If profile.module enabled, add profile forms.
if (module_exists('profile')) {
$form['enabled_forms']['profile_forms'] = array('#value' => '<h5>' . t('Profile Forms') . '</h5>');
$form['enabled_forms']['honeypot_form_user_profile_form'] = array(
'#type' => 'checkbox',
'#title' => t('Profile forms (all)'),
'#default_value' => variable_get('honeypot_form_user_profile_form', 0),
);
}
// Get node types for node forms and node comment forms.
$types = node_type_get_types();
if (!empty($types)) {
// Node forms.
$form['enabled_forms']['node_forms'] = array('#markup' => '<h5>' . t('Node Forms') . '</h5>');
foreach ($types as $type) {
$id = 'honeypot_form_' . $type->type . '_node_form';
$form['enabled_forms'][$id] = array(
'#type' => 'checkbox',
'#title' => t('@name node form', array('@name' => $type->name)),
'#default_value' => variable_get($id, 0),
);
}
// Comment forms.
if (module_exists('comment')) {
$form['enabled_forms']['comment_forms'] = array('#markup' => '<h5>' . t('Comment Forms') . '</h5>');
foreach ($types as $type) {
$id = 'honeypot_form_comment_node_' . $type->type . '_form';
$form['enabled_forms'][$id] = array(
'#type' => 'checkbox',
'#title' => t('@name comment form', array('@name' => $type->name)),
'#default_value' => variable_get($id, 0),
);
}
}
}
// Add our own submit handler to clear honeypot's form cache on save.
$form['#submit'][] = 'honeypot_admin_form_submit';
return system_settings_form($form);
}
/**
* Validate the admin form.
*/
function honeypot_admin_form_validate($form, &$form_state) {
// Make sure the time limit is a positive integer or 0.
$time_limit = $form_state['values']['honeypot_time_limit'];
if ((is_numeric($time_limit) && $time_limit > 0) || $time_limit === '0') {
if (ctype_digit($time_limit)) {
// Good to go.
}
else {
form_set_error('honeypot_time_limit', t("The time limit must be a positive integer or 0."));
}
}
else {
form_set_error('honeypot_time_limit', t("The time limit must be a positive integer or 0."));
}
// Make sure Honeypot element name only contains A-Z, 0-9.
if (!preg_match("/^[-_a-zA-Z0-9]+$/", $form_state['values']['honeypot_element_name'])) {
form_set_error('honeypot_element_name', t("The element name cannot contain spaces or other special characters."));
}
}
/**
* Clear the honeypot form cache on submit.
*/
function honeypot_admin_form_submit($form, &$form_state) {
cache_clear_all('honeypot_protected_forms', 'cache');
}

View File

@@ -0,0 +1,101 @@
<?php
/**
* @file
*
* API Functionality for Honeypot module.
*/
/**
* @addtogroup hooks
* @{
*/
/**
* Alter the honeypot protections added to a particular form.
*
* @param (array) $options
* Protections that will be applied to the form. May be empty, or may include
* 'honeypot' and/or 'time_restriction'.
* @param (array) $form
* The Form API form to which protections will be added.
*/
function hook_honeypot_form_protections_alter(&$options, $form) {
// Add 'time_restriction' protection to 'mymodule-form' if it's not set.
if ($form['form_id']['#value'] == 'mymodule_form' && !in_array('time_restriction', $options)) {
$options[] = 'time_restriction';
}
}
/**
* React to an addition of honeypot form protections for a given form_id.
*
* After honeypot has added its protections to a form, this hook will be called.
* You can use this hook to track when and how many times certain protected
* forms are displayed to certain users, or for other tracking purposes.
*
* @param (array) $options
* Protections that were applied to the form. Includes 'honeypot' and/or
* 'time_restriction'.
* @param (array) $form
* The Form API form to which protections were added.
*/
function hook_honeypot_add_form_protection($options, $form) {
if ($form['form_id']['#value'] == 'mymodule_form') {
// Do something...
}
}
/**
* React to the rejection of a form submission.
*
* When honeypot rejects a form submission, it calls this hook with the form ID,
* the user ID (0 if anonymous) of the user that was disallowed from submitting
* the form, and the reason (type) for the rejection of the form submission.
*
* @param (string) $form_id
* Form ID of the form the user was disallowed from submitting.
* @param (int) $uid
* 0 for anonymous users, otherwise the user ID of the user.
* @param (string) $type
* String indicating the reason the submission was blocked. Allowed values:
* - honeypot: If honeypot field was filled in.
* - honeypot_time: If form was completed before the configured time limit.
*/
function hook_honeypot_reject($form_id, $uid, $type) {
if ($form_id == 'mymodule_form') {
// Do something...
}
}
/**
* Add time to the Honeypot time limit.
*
* In certain circumstances (for example, on forms routinely targeted by
* spammers), you may want to add an additional time delay. You can use this
* hook to return additional time (in seconds) to honeypot when it is calculates
* the time limit for a particular form.
*
* @param (int) $honeypot_time_limit
* The current honeypot time limit (in seconds), to which any additions you
* return will be added.
* @param (array) $form_values
* Array of form values (may be empty).
* @param (int) $number
* Number of times the current user has already fallen into the honeypot trap.
*
* @return (int) $additions
* Additional time to add to the honeypot_time_limit, in seconds (integer).
*/
function hook_honeypot_time_limit($honeypot_time_limit, $form_values, $number) {
$additions = 0;
// If 'some_interesting_value' is set in your form, add 10 seconds to limit.
if (!empty($form_values['some_interesting_value']) && $form_values['some_interesting_value']) {
$additions = 10;
}
return $additions;
}
/**
* @} End of "addtogroup hooks".
*/

View File

@@ -0,0 +1,14 @@
name = Honeypot
description = "Mitigates spam form submissions using the honeypot method."
core = 7.x
configure = admin/config/content/honeypot
package = "Spam control"
files[] = honeypot.test
; Information added by drupal.org packaging script on 2013-09-13
version = "7.x-1.15"
core = "7.x"
project = "honeypot"
datestamp = "1379087801"

View File

@@ -0,0 +1,132 @@
<?php
/**
* @file
*
* Install, update and uninstall functions for the Honeypot module.
*/
/**
* Implements of hook_schema().
*/
function honeypot_schema() {
$schema['honeypot_user'] = array(
'description' => 'Table that stores failed attempts to submit a form.',
'fields' => array(
'uid' => array(
'description' => 'Foreign key to {users}.uid; uniquely identifies a Drupal user to whom this ACL data applies.',
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
),
'timestamp' => array(
'description' => 'Date/time when the form submission failed, as Unix timestamp.',
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
),
),
'indexes' => array(
'uid' => array('uid'),
'timestamp' => array('timestamp'),
),
);
return $schema;
}
/**
* Implements hook_install().
*/
function honeypot_install() {
drupal_set_message(st("Honeypot installed successfully. Please !link to protect your forms from spam bots.", array(
'!link' => l(st('configure Honeypot'), 'admin/config/content/honeypot')
)));
}
/**
* Implements hook_uninstall().
*/
function honeypot_uninstall() {
db_delete('variable')
->condition('name', db_like('honeypot_') . '%', 'LIKE')
->execute();
$cache_tables = array('variables', 'cache_bootstrap');
foreach ($cache_tables as $table) {
if (db_table_exists($table)) {
cache_clear_all($table, 'cache');
}
}
}
/**
* Implements hook_update_N().
*/
function honeypot_update_7001() {
$ret = array();
// Leaving this in because I had it in version 1.3. Silly me.
return $ret;
}
/**
* Update form names after upgrade from 6.x version.
*/
function honeypot_update_7002() {
$map = array(
'user_register' => 'user_register_form',
'contact_mail_page' => 'contact_site_form',
'contact_mail_user' => 'contact_personal_form',
);
foreach ($map as $d6_name => $d7_name) {
$value = variable_get('honeypot_form_' . $d6_name, 0);
if ($value) {
variable_set('honeypot_form_' . $d7_name, $value);
}
variable_del('honeypot_form_' . $d6_name);
}
$comment_form_value = variable_get('honeypot_form_comment_form', 0);
if ($comment_form_value) {
$types = node_type_get_types();
if (!empty($types)) {
foreach ($types as $type) {
$d7_name = 'honeypot_form_comment_node_' . $type->type . '_form';
variable_set($d7_name, $comment_form_value);
}
}
}
variable_del('honeypot_form_comment_form');
}
/**
* Add {honeypot_users} database table if it doesn't exist.
*/
function honeypot_update_7003() {
// Make sure the {honeypot_users} table doesn't already exist.
if (!db_table_exists('honeypot_user')) {
$table = array(
'description' => 'Table that stores failed attempts to submit a form.',
'fields' => array(
'uid' => array(
'description' => 'Foreign key to {users}.uid; uniquely identifies a Drupal user to whom this ACL data applies.',
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
),
'timestamp' => array(
'description' => 'Date/time when the form submission failed, as Unix timestamp.',
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
),
),
'indexes' => array(
'uid' => array('uid'),
'timestamp' => array('timestamp'),
),
);
db_create_table('honeypot_user', $table);
}
}

View File

@@ -0,0 +1,312 @@
<?php
/**
* @file
*
* Honeypot module, for deterring spam bots from completing Drupal forms.
*/
/**
* Implements hook_menu().
*/
function honeypot_menu() {
$items['admin/config/content/honeypot'] = array(
'title' => 'Honeypot configuration',
'description' => 'Configure Honeypot spam prevention and the forms on which Honeypot will be used.',
'page callback' => 'drupal_get_form',
'page arguments' => array('honeypot_admin_form'),
'access arguments' => array('administer honeypot'),
'file' => 'honeypot.admin.inc',
);
return $items;
}
/**
* Implements hook_permission().
*/
function honeypot_permission() {
return array(
'administer honeypot' => array(
'title' => t('Administer Honeypot'),
'description' => t('Administer Honeypot-protected forms and settings'),
),
'bypass honeypot protection' => array(
'title' => t('Bypass Honeypot protection'),
'description' => t('Bypass Honeypot form protection.'),
),
);
}
/**
* Implements of hook_cron().
*/
function honeypot_cron() {
// Delete {honeypot_user} entries older than the value of honeypot_expire.
db_delete('honeypot_user')
->condition('timestamp', time() - variable_get('honeypot_expire', 300), '<')
->execute();
}
/**
* Implements hook_form_alter().
*
* Add Honeypot features to forms enabled in the Honeypot admin interface.
*/
function honeypot_form_alter(&$form, &$form_state, $form_id) {
// Don't use for maintenance mode forms (install, update, etc.).
if (defined('MAINTENANCE_MODE')) {
return;
}
$unprotected_forms = array(
'user_login',
'user_login_block',
'search_form',
'search_block_form',
'views_exposed_form',
'honeypot_admin_form',
);
// If configured to protect all forms, add protection to every form.
if (variable_get('honeypot_protect_all_forms', 0) && !in_array($form_id, $unprotected_forms)) {
// Don't protect system forms - only admins should have access, and system
// forms may be programmatically submitted by drush and other modules.
if (strpos($form_id, 'system_') === FALSE && strpos($form_id, 'search_') === FALSE && strpos($form_id, 'views_exposed_form_') === FALSE) {
honeypot_add_form_protection($form, $form_state, array('honeypot', 'time_restriction'));
}
}
// Otherwise add form protection to admin-configured forms.
elseif ($forms_to_protect = honeypot_get_protected_forms()) {
foreach ($forms_to_protect as $protect_form_id) {
// For most forms, do a straight check on the form ID.
if ($form_id == $protect_form_id) {
honeypot_add_form_protection($form, $form_state, array('honeypot', 'time_restriction'));
}
// For webforms use a special check for variable form ID.
elseif ($protect_form_id == 'webforms' && (strpos($form_id, 'webform_client_form') !== FALSE)) {
honeypot_add_form_protection($form, $form_state, array('honeypot', 'time_restriction'));
}
}
}
}
/**
* Build an array of all the protected forms on the site, by form_id.
*
* @todo - Add in API call/hook to allow modules to add to this array.
*/
function honeypot_get_protected_forms() {
$forms = &drupal_static(__FUNCTION__);
// If the data isn't already in memory, get from cache or look it up fresh.
if (!isset($forms)) {
if ($cache = cache_get('honeypot_protected_forms')) {
$forms = $cache->data;
}
else {
// Look up all the honeypot forms in the variables table.
$result = db_query("SELECT name FROM {variable} WHERE name LIKE 'honeypot_form_%'")->fetchCol();
// Add each form that's enabled to the $forms array.
foreach ($result as $variable) {
if (variable_get($variable, 0)) {
$forms[] = substr($variable, 14);
}
}
// Save the cached data.
cache_set('honeypot_protected_forms', $forms, 'cache');
}
}
return $forms;
}
/**
* Form builder function to add different types of protection to forms.
*
* @param $options (array)
* Array of options to be added to form. Currently accepts 'honeypot' and
* 'time_restriction'.
*
* @return $form_elements
* Returns elements to be placed in a form's elements array to prevent spam.
*/
function honeypot_add_form_protection(&$form, &$form_state, $options = array()) {
global $user;
// Allow other modules to alter the protections applied to this form.
drupal_alter('honeypot_form_protections', $options, $form);
// Don't add any protections if the user can bypass the Honeypot.
if (user_access('bypass honeypot protection')) {
return;
}
// Build the honeypot element.
if (in_array('honeypot', $options)) {
// Get the element name (default is generic 'url').
$honeypot_element = variable_get('honeypot_element_name', 'url');
// Build the honeypot element.
$honeypot_class = $honeypot_element . '-textfield';
$form[$honeypot_element] = array(
'#type' => 'textfield',
'#title' => t('Leave this field blank'),
'#size' => 20,
'#weight' => 100,
'#attributes' => array('autocomplete' => 'off'),
'#element_validate' => array('_honeypot_honeypot_validate'),
'#prefix' => '<div class="' . $honeypot_class . '">',
'#suffix' => '</div>',
'#attached' => array(
'css' => array(
'.' . $honeypot_class . ' { display: none !important; }' => array('type' => 'inline'), // Hide honeypot.
),
),
);
}
// Build the time restriction element (if it's not disabled).
if (in_array('time_restriction', $options) && variable_get('honeypot_time_limit', 5) != 0) {
// Set the current time in a hidden value to be checked later.
$form['honeypot_time'] = array(
'#type' => 'hidden',
'#title' => t('Timestamp'),
'#default_value' => time(),
'#element_validate' => array('_honeypot_time_restriction_validate'),
);
// Disable page caching to make sure timestamp isn't cached.
if (user_is_anonymous()) {
$GLOBALS['conf']['cache'] = 0;
}
}
// Allow other modules to react to addition of form protection.
if (!empty($options)) {
module_invoke_all('honeypot_add_form_protection', $options, $form);
}
}
/**
* Validate honeypot field.
*/
function _honeypot_honeypot_validate($element, &$form_state) {
// Get the honeypot field value.
$honeypot_value = $element['#value'];
// Make sure it's empty.
if (!empty($honeypot_value)) {
_honeypot_log($form_state['values']['form_id'], 'honeypot');
form_set_error('', t('There was a problem with your form submission. Please refresh the page and try again.'));
}
}
/**
* Validate honeypot's time restriction field.
*/
function _honeypot_time_restriction_validate($form, &$form_state) {
// Get the time value.
$honeypot_time = $form_state['values']['honeypot_time'];
// Get the honeypot_time_limit.
$time_limit = honeypot_get_time_limit($form_state['values']);
// Make sure current time - (time_limit + form time value) is greater than 0.
// If not, throw an error.
if (time() < ($honeypot_time + $time_limit)) {
_honeypot_log($form_state['values']['form_id'], 'honeypot_time');
$time_limit = honeypot_get_time_limit();
$form_state['values']['honeypot_time'] = time();
form_set_error('', t('There was a problem with your form submission. Please wait @limit seconds and try again.', array('@limit' => $time_limit)));
}
}
/**
* Log blocked form submissions.
*
* @param $form_id
* Form ID for the form on which submission was blocked.
* @param $type
* String indicating the reason the submission was blocked. Allowed values:
* - honeypot: If honeypot field was filled in.
* - honeypot_time: If form was completed before the configured time limit.
*/
function _honeypot_log($form_id, $type) {
honeypot_log_failure($form_id, $type);
if (variable_get('honeypot_log', 0)) {
$variables = array(
'%form' => $form_id,
'@cause' => ($type == 'honeypot') ? t('submission of a value in the honeypot field') : t('submission of the form in less than minimum required time'),
);
watchdog('honeypot', 'Blocked submission of %form due to @cause.', $variables);
}
return;
}
/**
* Look up the time limit for the current user.
*
* @param $form_values
* Array of form values (optional).
*/
function honeypot_get_time_limit($form_values = array()) {
global $user;
$honeypot_time_limit = variable_get('honeypot_time_limit', 5);
// Only calculate time limit if honeypot_time_limit has a value > 0.
if ($honeypot_time_limit) {
// Get value from {honeypot_user} table for authenticated users.
if ($user->uid) {
$number = db_query("SELECT COUNT(*) FROM {honeypot_user} WHERE uid = :uid", array(':uid' => $user->uid))->fetchField();
}
// Get value from {flood} table for anonymous users.
else {
$number = db_query("SELECT COUNT(*) FROM {flood} WHERE event = :event AND identifier = :hostname AND timestamp > :time", array(
':event' => 'honeypot',
':hostname' => ip_address(),
':time' => time() - variable_get('honeypot_expire', 300),
))->fetchField();
}
// Don't add more than 30 days' worth of extra time.
$honeypot_time_limit = $honeypot_time_limit + (int) min($honeypot_time_limit + exp($number), 2592000);
$additions = module_invoke_all('honeypot_time_limit', $honeypot_time_limit, $form_values, $number);
if (count($additions)) {
$honeypot_time_limit += array_sum($additions);
}
}
return $honeypot_time_limit;
}
/**
* Log the failed submision with timestamp.
*
* @param $form_id
* Form ID for the rejected form submission.
* @param $type
* String indicating the reason the submission was blocked. Allowed values:
* - honeypot: If honeypot field was filled in.
* - honeypot_time: If form was completed before the configured time limit.
*/
function honeypot_log_failure($form_id, $type) {
global $user;
// Log failed submissions for authenticated users.
if ($user->uid) {
db_insert('honeypot_user')
->fields(array(
'uid' => $user->uid,
'timestamp' => time(),
))
->execute();
}
// Register flood event for anonymous users.
else {
flood_register_event('honeypot');
}
// Allow other modules to react to honeypot rejections.
module_invoke_all('honeypot_reject', $form_id, $user->uid, $type);
}

View File

@@ -0,0 +1,138 @@
<?php
/**
* @file
* Testing for Honeypot module.
*/
/**
* Test the functionality of the Honeypot module for an admin user.
*/
class HoneypotFormTestCase extends DrupalWebTestCase {
protected $admin_user;
protected $web_user;
protected $node;
public static function getInfo() {
return array(
'name' => 'Honeypot form protections',
'description' => 'Ensure that Honeypot protects site forms properly.',
'group' => 'Form API',
);
}
public function setUp() {
// Enable modules required for this test.
parent::setUp(array('honeypot', 'comment'));
// Set up required Honeypot variables.
variable_set('honeypot_element_name', 'url');
variable_set('honeypot_time_limit', 0); // Disable time_limit protection.
variable_set('honeypot_protect_all_forms', TRUE); // Test protecting all forms.
variable_set('honeypot_log', FALSE);
// Set up other required variables.
variable_set('user_email_verification', TRUE);
variable_set('user_register', USER_REGISTER_VISITORS);
// Set up admin user.
$this->admin_user = $this->drupalCreateUser(array(
'administer honeypot',
'bypass honeypot protection',
'administer content types',
'administer users',
'access comments',
'post comments',
'skip comment approval',
'administer comments',
));
// Set up web user.
$this->web_user = $this->drupalCreateUser(array(
'access comments',
'post comments',
'create article content',
));
// Set up example node.
$this->node = $this->drupalCreateNode(array(
'type' => 'article',
'promote' => 1,
'uid' => $this->web_user->uid,
));
}
/**
* Test user registration (anonymous users).
*/
public function testProtectRegisterUserNormal() {
// Set up form and submit it.
$edit['name'] = $this->randomName();
$edit['mail'] = $edit['name'] . '@example.com';
$this->drupalPost('user/register', $edit, t('Create new account'));
// Form should have been submitted successfully.
$this->assertText(t('A welcome message with further instructions has been sent to your e-mail address.'), 'User registered successfully.');
}
public function testProtectUserRegisterHoneypotFilled() {
// Set up form and submit it.
$edit['name'] = $this->randomName();
$edit['mail'] = $edit['name'] . '@example.com';
$edit['url'] = 'http://www.example.com/';
$this->drupalPost('user/register', $edit, t('Create new account'));
// Form should have error message.
$this->assertText(t('There was a problem with your form submission. Please refresh the page and try again.'), 'Registration form protected by honeypot.');
}
public function testProtectRegisterUserTooFast() {
// Enable time limit for honeypot.
variable_set('honeypot_time_limit', 5);
// Set up form and submit it.
$edit['name'] = $this->randomName();
$edit['mail'] = $edit['name'] . '@example.com';
$this->drupalPost('user/register', $edit, t('Create new account'));
// Form should have error message.
$this->assertText(t('There was a problem with your form submission. Please wait'), 'Registration form protected by time limit.');
}
public function testProtectCommentFormNormal() {
$comment = 'Test comment.';
// Disable time limit for honeypot.
variable_set('honeypot_time_limit', 0);
// Log in the web user.
$this->drupalLogin($this->web_user);
// Set up form and submit it.
$edit['comment_body[' . LANGUAGE_NONE . '][0][value]'] = $comment;
$this->drupalPost('comment/reply/' . $this->node->nid, $edit, t('Save'));
$this->assertText(t('Your comment has been posted.'), 'Comment posted successfully.');
}
public function testProtectCommentFormHoneypotFilled() {
$comment = 'Test comment.';
// Log in the web user.
$this->drupalLogin($this->web_user);
// Set up form and submit it.
$edit['comment_body[' . LANGUAGE_NONE . '][0][value]'] = $comment;
$edit['url'] = 'http://www.example.com/';
$this->drupalPost('comment/reply/' . $this->node->nid, $edit, t('Save'));
$this->assertText(t('There was a problem with your form submission. Please refresh the page and try again.'), 'Comment posted successfully.');
}
public function testProtectCommentFormHoneypotBypass() {
// Log in the admin user.
$this->drupalLogin($this->admin_user);
// Get the comment reply form and ensure there's no 'url' field.
$this->drupalGet('comment/reply/' . $this->node->nid);
$this->assertNoText('id="edit-url" name="url"', 'Honeypot home page field not shown.');
}
}

View File

@@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

View File

@@ -0,0 +1,5 @@
== SUMMARY ==
This is an API module which lets you put several forms into one <form>.
== USAGE ==
For code example, check multiform.example.inc file.

View File

@@ -0,0 +1,41 @@
<?php
/**
* @file
*
*
*
* @author Kálmán Hosszu - hosszu.kalman@gmail.com - http://premiumcmsthemes.com http://www.kalman-hosszu.com
*/
function multiform_test_menu() {
return array(
'multiform_test' => array(
'access callback' => TRUE,
'type' => MENU_CALLBACK,
'page callback' => 'multiform_get_form',
'page arguments' => array(array('multiform_eaxample_test1'), array('multiform_test2')),
),
);
}
function multiform_test1($form, $form_state) {
$form['test1'] = array('#type' => 'textfield', '#title' => 'test1');
$form['submit'] = array('#type' => 'submit', '#value' => 'save', '#submit' => array('multiform_test_submit_button'));
$form['delete'] = array('#type' => 'submit', '#value' => 'delete', '#submit' => array('multiform_test_delete'));
return $form;
}
function multiform_test2($form) {
$form['submit'] = array('#type' => 'submit', '#value' => 'save', '#submit' => array('multiform_test_submit_button'));
$form['delete'] = array('#type' => 'submit', '#value' => 'delete', '#submit' => array('multiform_test_delete'));
$form['test2'] = array('#type' => 'textfield', '#title' => 'test2');
return $form;
}
function multiform_test_submit_button($form, $form_state) {
drupal_set_message($form['#form_id'] . 'multiform_test_submit_button');
}
function multiform_test_delete($form, $form_state) {
drupal_set_message($form['#form_id'] . 'multiform_test_delete');
}

View File

@@ -0,0 +1,13 @@
name = Multiple forms
description = Allows displaying and submitting multiple forms in one form
files[] = multiform.module
files[] = tests/multiform.test
core = 7.x
; Information added by drupal.org packaging script on 2012-01-29
version = "7.x-1.0"
core = "7.x"
project = "multiform"
datestamp = "1327823749"

View File

@@ -0,0 +1,140 @@
<?php
/**
* Returns a form containing a number of other forms.
*
* When the forms are submitted their first button is pressed in array order.
* Make sure you rearrange the buttons in your form accordingly in a form_alter
* when using this function.
*
* @param ...
* Every argument is a list of arguments to be passed to drupal_get_form.
* For example, if the first form is called as
* drupal_get_form($form_id1, $arg1, $arg2); and
* the second as drupal_get_form($form_id2, $arg3, $arg4) call
* multiform_get_form(array($form_id1, $arg1, $arg2), array($form_id2, $arg3, $arg4)).
*/
function multiform_get_form() {
$all_args = func_get_args();
$redirect = NULL;
$form = element_info('form');
$form['#id'] = 'multiform';
$form['#attributes'] = array();
// We need a $form_id so that the submission of other forms (like search) do
// not disturb us.
$form['form_id'] = array(
'#type' => 'hidden',
'#value' => 'multiform',
'#id' => drupal_html_id("edit-multiform"),
'#name' => 'form_id',
'#attributes' => array(),
);
$build_id = 'form-' . md5(uniqid(mt_rand(), TRUE));
// We need a $form_build_id because the buttons are cached and the values
// belonging to them in $_POST are handed to each form so those can recognize
// the buttons pressed.
$form['form_build_id'] = array(
'#type' => 'hidden',
'#value' => $build_id,
'#id' => $build_id,
'#name' => 'form_build_id',
'#attributes' => array(),
);
// This is where buttons will be collected.
$form['buttons'] = array();
$form['buttons']['#weight'] = 1000;
$form_state_save = array();
$button_names = array();
// The only way to support $_GET would be to accept $form_state. Maybe later.
if ($_POST && $_POST['form_id'] == 'multiform' && !empty($_POST['form_build_id'])) {
$form_state_save['input'] = $_POST;
$_files_save = $_FILES;
// Retrieve buttons.
if ($button_elements = form_get_cache($_POST['form_build_id'], $form_state_save)) {
foreach ($button_elements as $button) {
// For each button, save it's name. Later on we will need the button
// names because the buttons are used in the multiform but their values
// in $_POST (if it exists) needs to be handed down to each form so
// those can recognize the button press.
$name = isset($button_elements['#name']) ? $button_elements['#name'] : 'op';
$button_names[$name] = $name;
}
}
}
foreach ($all_args as $key => $args) {
$form_id = array_shift($args);
// Reset $form_state and disable redirection.
$form_state = array('no_redirect' => TRUE);
// This line is copied literally from drupal_get_form().
$form_state['build_info']['args'] = $args;
$index = $form_id . '_' . $key;
if (isset($form_state_save['input']['multiform'][$index])) {
// drupal_build_form() honors our $form_state['input'] setup.
$form_state['input'] = $form_state_save['input']['multiform'][$index];
// Pass in the information about pressed buttons too.
foreach ($button_names as $name) {
if (isset($form_state_save['input'][$name])) {
$form_state['input'][$name] = $form_state_save['input'][$name];
}
}
}
if (isset($_files_save['multiform']['name'][$index])) {
$_FILES = array();
foreach (array('name', 'type', 'tmp_name', 'error', 'size') as $files_key) {
// PHP is seriously messed up, dude.
foreach ($_files_save['multiform'][$files_key][$index] as $running_out_of_indexes => $data) {
$_FILES[$running_out_of_indexes][$files_key] = $data;
}
}
}
// Build and process this form.
$current_form = drupal_build_form($form_id, $form_state);
// Do not render the <form> tags. Instead we render the <form> as a <div>.
$current_form['#theme_wrappers'] = array('container');
_multiform_get_form($current_form, $form['buttons'], $index);
// Unset any attributes specifics to form tags.
$disallowed_attributes = array('enctype', 'action', 'method');
$current_form['#attributes'] = array_diff_key($current_form['#attributes'], array_flip($disallowed_attributes));
$form['multiform'][$index] = $current_form;
if (isset($form_state['has_file_element'])) {
$form['#attributes']['enctype'] = 'multipart/form-data';
}
// Keep the redirect from the first form.
if (!$key) {
$redirect = isset($form_state['redirect']) ? $form_state : array();
}
}
form_set_cache($build_id, $form['buttons'], $form_state_save);
if (!empty($form_state_save['input'])) {
// We forced $form_state['no_redirect'] to TRUE above, so unset it in order
// to allow the redirection to proceed.
unset($redirect['no_redirect']);
drupal_redirect_form($redirect);
}
return $form;
}
/**
* Recursive helper for multiform_get_form().
*/
function _multiform_get_form(&$element, &$buttons, $form_id) {
// Recurse.
foreach (element_children($element) as $key) {
_multiform_get_form($element[$key], $buttons, $form_id);
}
// Save but do not display buttons. Note that this is done before the #name
// is changed. This way the buttons belong to the top form and their values
// can be handed to each form.
if (isset($element['#button_type'])) {
$buttons[$element['#value']] = $element;
$element['#access'] = FALSE;
}
// By only changing $element['#name'] form API is not affected but the
// browser will put the element values into _POST where multiform_get_form
// expects them.
elseif (isset($element['#name'])) {
// If the name was op then we want multiform[$form_id][op]. If it was
// foo[bar] then we want multiform[$form_id][foo][bar].
$element['#name'] = "multiform[$form_id]" . preg_replace('/^[^[]+/', '[\0]', $element['#name']);
}
}

View File

@@ -0,0 +1,104 @@
<?php
/**
* @file
*
*
*
* @author Kálmán Hosszu - hosszu.kalman@gmail.com - http://premiumcmsthemes.com http://www.kalman-hosszu.com
*/
class MultiformTestCase extends DrupalWebTestCase {
/**
* Info method.
*
* @return array
*/
public static function getInfo() {
return array(
'name' => 'Forms functionality',
'description' => 'Testing multiform functionality.' ,
'group' => 'Multiform',
);
}
/**
* Overriden setUp function.
*/
public function setUp() {
parent::setUp('multiform', 'multiform_test');
}
/**
* Check various submit ops.
*/
public function testSubmitHandling() {
// Go to the form page.
$this->drupalGet('multiform-test/1');
// Check buttons.
$this->assertFieldByName('op', 'save');
$this->assertFieldByName('op', 'delete');
// No more buttons.
$submitButtons = $this->xpath('//input[@type="submit" and @name!="op"]');
$this->assertEqual(count($submitButtons), 0, t('No more submit button.'));
// Save button.
$this->drupalPost(NULL, array(), 'save');
$this->assertText('multiform_test1_1multiform_test1_submit_button', t('First form save message is found.'));
$this->assertText('multiform_test1_2multiform_test1_submit_button', t('Second form save message is found.'));
// Delete button.
$this->drupalPost(NULL, array(), 'delete');
$this->assertText('multiform_test1_1multiform_test1_delete_button', t('First form delete message is found.'));
$this->assertText('multiform_test1_2multiform_test1_delete_button', t('Second form delete message is found.'));
}
/**
* Check the merged fields exist.
*/
public function testFieldsAreExist() {
// Go to the form page.
$this->drupalGet('multiform-test/2');
// Check textfields.
$this->assertFieldByName('multiform[multiform_test2_1_0][required_text_1]');
$this->assertFieldByName('multiform[multiform_test2_2_1][required_text_2]');
// Check button.
$this->assertFieldByName('op', 'save');
}
/**
* Check required fields.
*/
public function testRequiredFields() {
$first_text = array('multiform[multiform_test2_1_0][required_text_1]' => 'test1 value');
$second_text = array('multiform[multiform_test2_2_1][required_text_2]' => 'test2 value');
// No required fields.
$this->drupalPost('multiform-test/2', array(), 'save');
$this->assertText('test1 field is required.');
$this->assertText('test2 field is required.');
$this->assertNoText('multiform_test2_1multiform_test2_submit_button');
$this->assertNoText('multiform_test2_2multiform_test2_submit_button');
// Send all required fields.
$this->drupalPost(NULL, array_merge($first_text, $second_text), 'save');
$this->assertText('multiform_test2_1multiform_test2_submit_button');
$this->assertText('multiform_test2_2multiform_test2_submit_button');
$this->assertNoText('test1 field is required.');
$this->assertNoText('test2 field is required.');
// Send first form's required field.
$this->drupalPost(NULL, $first_text, 'save');
$this->assertNoText('multiform_test2_1multiform_test2_submit_button');
$this->assertText('test2 field is required.');
// Send second form's required field.
$this->drupalPost(NULL, $second_text, 'save');
$this->assertNoText('multiform_test2_2multiform_test2_submit_button');
$this->assertText('test1 field is required.');
}
}

View File

@@ -0,0 +1,14 @@
name = Multiform test
description = Handle module for testing Multiform
core = 7.x
dependencies[] = multiform
hidden = TRUE
files[] = multiform_test.module
; Information added by drupal.org packaging script on 2012-01-29
version = "7.x-1.0"
core = "7.x"
project = "multiform"
datestamp = "1327823749"

View File

@@ -0,0 +1,171 @@
<?php
/**
* @file
*
*
*
* @author Kálmán Hosszu - hosszu.kalman@gmail.com - http://premiumcmsthemes.com http://www.kalman-hosszu.com
*/
/* ====================== */
/* ==== DRUPAL HOOKS ==== */
/* ====================== */
/**
* Implementation of hook_menu().
*
* @return An array of menu items.
*/
function multiform_test_menu() {
$items = array();
$items['multiform-test/1'] = array(
'title' => 'Multiform test page 1',
'page callback' => 'multiform_get_form',
'page arguments' => array(array('multiform_test1_1'), array('multiform_test1_2')),
'access callback' => TRUE,
'type' => MENU_CALLBACK,
);
$items['multiform-test/2'] = array(
'title' => 'Multiform test page 2',
'page callback' => 'multiform_get_form',
'page arguments' => array(array('multiform_test2_1'), array('multiform_test2_2')),
'access callback' => TRUE,
'type' => MENU_CALLBACK,
);
return $items;
}
/* ====================== */
/* == MODULE FUNCTIONS == */
/* ====================== */
/* FIRST TEST CASE */
/**
* Build multiform_test1_1 form.
*
* @param type $form
* @param type $form_state
* @return array
*/
function multiform_test1_1($form, $form_state) {
$form['submit'] = array(
'#type' => 'submit',
'#value' => 'save',
'#submit' => array('multiform_test1_submit_button'),
);
$form['delete'] = array(
'#type' => 'submit',
'#value' => 'delete',
'#submit' => array('multiform_test1_delete_button'),
);
return $form;
}
/**
* Build multiform_test1_2 form.
*
* @param type $form
* @param type $form_state
* @return string
*/
function multiform_test1_2($form, $form_state) {
$form['submit'] = array(
'#type' => 'submit',
'#value' => 'save',
'#submit' => array('multiform_test1_submit_button'),
);
$form['delete'] = array(
'#type' => 'submit',
'#value' => 'delete',
'#submit' => array('multiform_test1_delete_button'),
);
return $form;
}
/**
* Submit handing.
*
* @param type $form
* @param type $form_state
*/
function multiform_test1_submit_button($form, $form_state) {
drupal_set_message($form['#form_id'] . 'multiform_test1_submit_button');
}
/**
* Handling delete.
*
* @param type $form
* @param type $form_state
*/
function multiform_test1_delete_button($form, $form_state) {
drupal_set_message($form['#form_id'] . 'multiform_test1_delete_button');
}
/* SECOND TEST CASE */
/**
* Build multiform_test2_1 form.
*
* @param type $form
* @param type $form_state
* @return array
*/
function multiform_test2_1($form, $form_state) {
$form['required_text_1'] = array(
'#type' => 'textfield',
'#title' => 'test1',
'#required' => TRUE,
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => 'save',
'#submit' => array('multiform_test2_submit_button'),
);
return $form;
}
/**
* Build multiform_test2_2 form.
*
* @param type $form
* @param type $form_state
* @return array
*/
function multiform_test2_2($form, $form_state) {
$form['required_text_2'] = array(
'#type' => 'textfield',
'#title' => 'test2',
'#required' => TRUE,
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => 'save',
'#submit' => array('multiform_test2_submit_button'),
);
return $form;
}
/**
* Submit handing.
*
* @param type $form
* @param type $form_state
*/
function multiform_test2_submit_button($form, $form_state) {
drupal_set_message($form['#form_id'] . 'multiform_test2_submit_button');
}

View File

@@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

View File

@@ -0,0 +1,62 @@
About the International Phone Number format
===========================================
These rules have been formulated off of the E.123 (for display) and
E.164 (for input) specifications published by the ITU. In order to
prevent ambiguity, we have chosen to restrict some of the stipulations
these specifications give.
In summary, country calling codes are assigned by the ITU Telecommunication
Standardization Sector in E.164. We take an international phone number to
have the form +XX YYYYYYY where XX is the country code, and YYYYYYY to be
the subscriber's number, possibly with intervening spaces. The maximum
length for these phone numbers is 15.
Reference materials can be found here:
- http://www.itu.int/rec/T-REC-E.123/en
- http://www.itu.int/rec/T-REC-E.164/en
Modifications to E.123
----------------------
7.1: The international prefix symbol "+" MUST prefix international
phone numbers. All numbers missing this symbol will be assumed to be in
the default country code.
When reformatting numbers to a standard format, the following conventions
will be taken:
7.2: Parentheses will be normalized to spaces.
We do not support the multiple phone numbers as described by (7.4); users
can always specify that multiple values are allowed if this is desired.
The functionality specified by 7.5, 7.6 and 8 IS NOT implemented.
9.2 specifies that spacing SHALL OCCUR between the country code, the trunk
code and the subscriber number. As trunk codes are omitted by convention,
this means the only guaranteed separation will be between the country code
and subscriber number. Our implementation MAY treat hyphens, spaces and
parentheses as advisory indicators as to where spaces should be placed.
However, +1 7329060489 will stay as it was specified, while +1 (732) 906-0489
will be normalized to +1 732 906 0489. As a future feature, rules may
be implemented for country codes specifying these conventions, however,
I have deemed such functionality out of scope for now.
The Drupal task specifies that we should validate country codes, however,
due to the highly volatile nature of these codes, the author does not
believe that it is a good idea to maintain a list of valid country codes.
Thus, we only validate that the country code is three or less digits.
Modifications to E.164
----------------------
Our processing for NDD's will be similarly constrained. As per
7.3.2, we will treat 0 as a valid trunk code for all countries.
Other digits may be specified if the fall in the form of (X), where X is
a single digit that is 7 or 8.
Postscript
----------
Modifications to our implementation will occur as necessary by user bug
reports.

View File

@@ -0,0 +1,84 @@
Copyright 2010 http://www.arvoriad.com
Description
-----------
This module provides a phone field type for CCK.
Features:
---------
* Validation of phone numbers : support of
+ France,
+ Belgium,
+ Great Britain,
+ Switzerland,
+ Italy,
+ Greece,
+ Netherland,
+ Israel,
+ Russia,
+ Ukraine,
+ Australia
+ Spain,
+ Czech,
+ Hungary,
+ Poland (mobile only),
+ Costa Rica,
+ Panamana,
+ Brazil,
+ Chili,
+ New Zealand,
+ China,
+ Hong-Kong,
+ Macau,
+ Philippine,
+ Singapore,
+ US,
+ Swiss,
+ Jordan,
+ Egypt,
+ South Africa,
+ Pakistan,
and Canadian phone numbers
and generic international phone numbers
* Formating of phone numbers
* Option for internationalization of phone numbers
* IPhone support
* Phone CCK fields can be used as a Token
* This module is compatible with module http://drupal.org/project/node_import Node Import module, this module allowing to import data into phone fields
Prerequisites
-------------
The phone.module requires the content.module to be installed.
Installation
------------
To install, copy the phone directory and all its contents to your modules
directory.
Configuration
-------------
To enable this module, visit administer -> modules, and enable phone.
Bugs/Features/Patches:
----------------------
If you want to report bugs, feature requests, or submit a patch, please do so
at the project page on the Drupal web site.
http://drupal.org/project/phone
Todo List:
----------
* add support to other country phone numbers
* improve the validation of phone numbers for the different countries
* internationalization of the module
Author
------
Thierry Guégan (http://www.arvoriad.com)
If you use this module, find it useful, and want to send the author
a thank you note, then use the Feedback/Contact page at the URL above.
The author can also be contacted for paid customizations of this
and other modules.

View File

@@ -0,0 +1,46 @@
ad => Andorran
ar => Argentinan
au => Australia
bd => Bangladesh
be => Belgium
bn => Brunei
br => Brazil
by => Belarussia
ca => Canadian
ca => US & Canada
ch => Switzerland
cl => Chili
cr => Costa Rica
cs => Czech Republic
cy => Cyprus
de => Germany
dk => Danish
dz => Algeria
ee => Estonia
eg => Egypt
es => Spain
fr => France
gp => Guadeloupe
gw => Guinea Bissau
hk => Hong-Kong
hr => Croatia
hu => Hungary
il => Israel
in => India
it => Italy
jo => Jordania
mo => Macao
nl => Netherland
nz => New Zealand
pa => Panamana
ph => Philippine
pk => Pakistan
pl => Poland
pt => Portugal
ru => Russia
se => Sweden
sg => Singapore
sn => Senegal
ua => Ukraine
uk => United Kingdom
us => US

View File

@@ -0,0 +1,283 @@
<?php
/**
* @file
* CCK Field for Australian phone numbers.
*/
function phone_au_metadata() {
return array(
'error' => '"%value" is not a valid Australian phone number<br>Australian phone numbers should contain only numbers with an optional prefix of "+61"',
);
}
/**
* Verification for Australian Phone Numbers.
* According to http://www.itu.int/itudoc/itu-t/number/a/aus/70772.html
* (Released 2005/10/03, retrieved 2008/04/14)
*
* @param string $phonenumber
* @return boolean Returns boolean FALSE if the phone number is not valid.
*/
function valid_au_phone_number($phonenumber) {
//$phonenumber = trim($phonenumber);
// strip formatting chars
$phonenumber = preg_replace('/[\-() ]/', '', $phonenumber);
// strip optional '+61' or '0' prefixes
$phonenumber = preg_replace('/^(\+61|0)/', '', $phonenumber);
//$rules[] = array("Prefix","Minimum length","Maximum length");
$rules[] = array("10", 5, 15);
$rules[] = array("12", 5, 15);
$rules[] = array("13", 6, 10);
$rules[] = array("1451", 9, 9);
$rules[] = array("1452", 9, 9);
$rules[] = array("1453", 9, 9);
$rules[] = array("1471", 9, 9);
$rules[] = array("16", 5, 9);
$rules[] = array("1800", 10, 10);
$rules[] = array("1801", 8, 8);
$rules[] = array("1900", 10, 10);
$rules[] = array("1901", 10, 10);
$rules[] = array("1902", 10, 10);
$rules[] = array("1906", 10, 10);
$rules[] = array("1983", 9, 9);
$rules[] = array("2001", 4, 4);
$rules[] = array("2002", 4, 4);
$rules[] = array("2003", 4, 4);
//$rules[] = array("2", 9, 9); // More specific rules follow
$rules[] = array("240", 9, 9);
$rules[] = array("242", 9, 9);
$rules[] = array("243", 9, 9);
$rules[] = array("244", 9, 9);
$rules[] = array("245", 9, 9);
$rules[] = array("246", 9, 9);
$rules[] = array("247", 9, 9);
$rules[] = array("248", 9, 9);
$rules[] = array("249", 9, 9);
$rules[] = array("260", 9, 9);
$rules[] = array("261", 9, 9);
$rules[] = array("262", 9, 9);
$rules[] = array("263", 9, 9);
$rules[] = array("264", 9, 9);
$rules[] = array("265", 9, 9);
$rules[] = array("266", 9, 9);
$rules[] = array("267", 9, 9);
$rules[] = array("268", 9, 9);
$rules[] = array("269", 9, 9);
$rules[] = array("28", 9, 9);
$rules[] = array("29", 9, 9);
//$rules[] = array("3", 9, 9); // More specific rules follow
$rules[] = array("350", 9, 9);
$rules[] = array("351", 9, 9);
$rules[] = array("352", 9, 9);
$rules[] = array("353", 9, 9);
$rules[] = array("354", 9, 9);
$rules[] = array("355", 9, 9);
$rules[] = array("356", 9, 9);
$rules[] = array("357", 9, 9);
$rules[] = array("358", 9, 9);
$rules[] = array("359", 9, 9);
$rules[] = array("362", 9, 9);
$rules[] = array("363", 9, 9);
$rules[] = array("364", 9, 9);
$rules[] = array("38", 9, 9);
$rules[] = array("39", 9, 9);
// begin mobile phone numbers
$rules[] = array("400", 9, 9);
$rules[] = array("401", 9, 9);
$rules[] = array("402", 9, 9);
$rules[] = array("403", 9, 9);
$rules[] = array("404", 9, 9);
$rules[] = array("405", 9, 9);
$rules[] = array("406", 9, 9);
$rules[] = array("407", 9, 9);
$rules[] = array("408", 9, 9);
$rules[] = array("409", 9, 9);
$rules[] = array("410", 9, 9);
$rules[] = array("411", 9, 9);
$rules[] = array("412", 9, 9);
$rules[] = array("413", 9, 9);
$rules[] = array("414", 9, 9);
$rules[] = array("415", 9, 9);
$rules[] = array("416", 9, 9);
$rules[] = array("417", 9, 9);
$rules[] = array("418", 9, 9);
$rules[] = array("419", 9, 9);
$rules[] = array("420", 9, 9);
$rules[] = array("4200", 9, 9);
$rules[] = array("42010", 9, 9);
$rules[] = array("421", 9, 9);
$rules[] = array("422", 9, 9);
$rules[] = array("423", 9, 9);
$rules[] = array("424", 9, 9);
$rules[] = array("425", 9, 9);
$rules[] = array("4251", 9, 9);
$rules[] = array("4252", 9, 9);
$rules[] = array("4253", 9, 9);
$rules[] = array("4256", 9, 9);
$rules[] = array("4257", 9, 9);
$rules[] = array("4258", 9, 9);
$rules[] = array("427", 9, 9);
$rules[] = array("428", 9, 9);
$rules[] = array("429", 9, 9);
$rules[] = array("430", 9, 9);
$rules[] = array("4300", 9, 9);
$rules[] = array("4301", 9, 9);
$rules[] = array("4302", 9, 9);
$rules[] = array("4303", 9, 9);
$rules[] = array("4304", 9, 9);
$rules[] = array("4305", 9, 9);
$rules[] = array("431", 9, 9);
$rules[] = array("432", 9, 9);
$rules[] = array("433", 9, 9);
$rules[] = array("434", 9, 9);
$rules[] = array("435", 9, 9);
$rules[] = array("4350", 9, 9);
$rules[] = array("437", 9, 9);
$rules[] = array("438", 9, 9);
$rules[] = array("439", 9, 9);
$rules[] = array("447", 9, 9);
$rules[] = array("448", 9, 9);
$rules[] = array("449", 9, 9);
$rules[] = array("449", 9, 9);
$rules[] = array("450", 9, 9);
$rules[] = array("451", 9, 9);
$rules[] = array("457", 9, 9);
$rules[] = array("458", 9, 9);
$rules[] = array("4590", 9, 9);
$rules[] = array("4591", 9, 9);
$rules[] = array("4592", 9, 9);
$rules[] = array("466", 9, 9);
$rules[] = array("488", 9, 9);
// end mobile phone numbers
$rules[] = array("50", 9, 9);
$rules[] = array("51", 9, 9);
$rules[] = array("52", 9, 9);
$rules[] = array("53", 9, 9);
$rules[] = array("54", 9, 9);
$rules[] = array("55", 9, 9);
$rules[] = array("56", 9, 9);
$rules[] = array("57", 9, 9);
$rules[] = array("58", 9, 9);
//$rules[] = array("59", 9, 9); //Not for use after 31 December 2005
//$rules[] = array("7", 9, 9); // More specific rules follow
$rules[] = array("73", 9, 9);
$rules[] = array("740", 9, 9);
$rules[] = array("741", 9, 9);
$rules[] = array("745", 9, 9);
$rules[] = array("746", 9, 9);
$rules[] = array("747", 9, 9);
$rules[] = array("749", 9, 9);
$rules[] = array("754", 9, 9);
$rules[] = array("755", 9, 9);
$rules[] = array("756", 9, 9);
//$rules[] = array("8", 9, 9); // More specific rules follow
$rules[] = array("86", 9, 9);
$rules[] = array("871", 9, 9);
$rules[] = array("872", 9, 9);
$rules[] = array("873", 9, 9);
$rules[] = array("874", 9, 9);
$rules[] = array("880", 9, 9);
$rules[] = array("881", 9, 9);
$rules[] = array("882", 9, 9);
$rules[] = array("883", 9, 9);
$rules[] = array("884", 9, 9);
$rules[] = array("885", 9, 9);
$rules[] = array("886", 9, 9);
$rules[] = array("887", 9, 9);
$rules[] = array("888", 9, 9);
$rules[] = array("889", 9, 9);
$rules[] = array("890", 9, 9);
$rules[] = array("891", 9, 9);
$rules[] = array("892", 9, 9);
$rules[] = array("893", 9, 9);
$rules[] = array("894", 9, 9);
$rules[] = array("895", 9, 9);
$rules[] = array("896", 9, 9);
$rules[] = array("897", 9, 9);
$rules[] = array("898", 9, 9);
$rules[] = array("899", 9, 9);
foreach ($rules as $rule) {
if (preg_match('/^'.$rule[0].'/', $phonenumber) && strlen($phonenumber) >= $rule[1] && strlen($phonenumber) <= $rule[2]) {
return TRUE;
}
}
return FALSE;
}
/**
* Formatting for Australian Phone Numbers. Based upon ITU-T E.123 (but let's not get too crazy)
*
* @param string $phonenumber
* @return string Returns a string containing the phone number with some formatting.
*/
function format_au_phone_number($phonenumber, $field = FALSE) {
$prefix = '';
$extension = '';
// strip old formatting chars
$phonenumber = preg_replace('/[\-() ]/', '', $phonenumber);
/*
* strip and save the +61 prefix if found
*/
if (preg_match('/^\+61/', $phonenumber, $match)) {
$prefix = '+61 ';
$phonenumber = str_replace('+61', '', $phonenumber);
}
/*
* strip and save the extension (x9999) postfix if found
*/
if (preg_match('/(x[0-9]+)$/', $phonenumber, $match)) {
$extension = ' ('.$match[1].')';
$phonenumber = preg_replace('/x[0-9]+$/', '', $phonenumber);
}
/*
* geographic numbers and UPT
* Eg. (02) 9999 9999 or +61 (2) 9999 9999
*/
if (preg_match('/^(0{0,1}[23578])([0-9]{4})([0-9]{4})$/', $phonenumber, $match)) {
return $prefix . '(' . $match[1] . ') ' . $match[2] . ' ' . $match[3] . $extension;
}
/*
* mobile numbers
* Eg. 0423 999 999 or +61 423 999 999
*/
if (preg_match('/^(0{0,1}4[0-9]{2})([0-9]{3})([0-9]{3})$/', $phonenumber, $match)) {
return $prefix . $match[1] . ' ' . $match[2] . ' ' . $match[3] . $extension;
}
/*
* 10 digit numbers
* Eg. 1800 999 999
*/
if (preg_match('/^([0-9]{4})([0-9]{3})([0-9]{3})$/', $phonenumber, $match)) {
return $prefix . $match[1] . ' ' . $match[2] . ' ' . $match[3] . $extension;
}
/*
* 9 digit satellite or dialup data numbers
* Eg. 1471 99999
*/
if (preg_match('/^(14[0-9]{2}|1983)([0-9]{5})$/', $phonenumber, $match)) {
return $prefix . $match[1] . ' ' . $match[2] . $extension;
}
/*
* 6 digit numbers
* Eg. 13 99 99
*/
if (preg_match('/^([0-9]{2})([0-9]{2})([0-9]{2})$/', $phonenumber, $match)) {
return $prefix . $match[1] . ' ' . $match[2] . ' ' . $match[3] . $extension;
}
// default
return $prefix . $phonenumber . $extension;
}

View File

@@ -0,0 +1,48 @@
<?php
/**
* @file
* CCK Field for Belgian phone numbers.
*/
function phone_be_metadata() {
// These strings are translated using t() on output.
return array(
'error' => '"%value" is not a valid Belgian phone number<br>Belgian phone numbers should only ...',
);
}
/**
* Verifies that $phonenumber is valid
*
* @param string $phonenumber
* @return boolean Returns boolean FALSE if the phone number is not valid.
*/
function valid_be_phone_number($phonenumber) {
// define regular expression
$regex = "/^(\+32|0)[1-9]\d{7,8}$/i";
$phonenumber = str_replace(array(' ','-','(',')'), '', $phonenumber);
// return true if valid, false otherwise
return (bool) preg_match($regex, $phonenumber);
}
/**
* Formatting for Belgian Phone Numbers.
*
* @param string $phonenumber
* @return string Returns a string containting the phone number with some formatting.
*/
function format_be_phone_number($phonenumber, $field) {
$phonenumber = trim($phonenumber);
if ($field['phone_country_code']) {
if ($matches[1] != "+32") {
$phonenumber = "+32" . " " . $phonenumber;
}
}
return $phonenumber;
}

View File

@@ -0,0 +1,51 @@
<?php
/**
* @file
* CCK Field for Brazilian phone numbers.
* (based on CCK Field for French phone numbers.)
*/
define('PHONE_BR_REGEX', "/^(\+|0{2}|)?(55|0|)[\s.-]?((\(0?[1-9][0-9]\))|(0?[1-9][0-9]))[\s.-]?([1-9][0-9]{2,4})[\s.-]?([0-9]{4})$/");
function phone_br_metadata() {
return array(
'error' => '"%value" is not a valid Brazilian phone number<br>Brazilian phone numbers should contain only numbers and spaces and - and be like 099 9999-9999, 99 9999-9999 or 99 99999-9999 with an optional prefix of "+55".',
);
}
/**
* Verification for Brazilian Phone Numbers.
*
* @param string $phonenumber
* @return boolean Returns boolean FALSE if the phone number is not valid.
*/
function valid_br_phone_number($phonenumber) {
$phonenumber = trim($phonenumber);
/*
$phonenumber = str_replace(array(' ','-','(',')'), '', $phonenumber);
*/
return (bool) preg_match(PHONE_BR_REGEX, $phonenumber);
}
/**
* Formatting for Brazilian Phone Numbers.
*
* @param string $phonenumber
* @return string Returns a string containting the phone number with some formatting.
*/
function format_br_phone_number($phonenumber, $field = FALSE) {
$phone = str_replace(array(' ','-','(',')'), '', $phonenumber);
if (preg_match(PHONE_BR_REGEX, $phone, $matches) != 1) {
return $phonenumber; // this is possible?
}
$formatedphone = '';
if ($field && $field['phone_country_code']) {
$formatedphone .= '+55 ';
}
$formatedphone .= '(' . $matches[3] . ')';
$formatedphone .= ' ' . $matches[6] . '-';
$formatedphone .= '' . $matches[7];
return $formatedphone;
}

View File

@@ -0,0 +1,91 @@
<?php
/**
* @file
* CCK Field for Canadian phone numbers.
*/
function phone_ca_metadata() {
return array(
'error' => '"%value" is not a valid North American phone number<br>North American Phone numbers should only contain numbers and + and - and ( and ) and spaces and be like 999-999-9999. Please enter a valid ten-digit phone number with optional extension.',
);
}
/**
* Verifies that $phonenumber is a valid ten-digit North American phone number
*
* @param string $phonenumber
* @return boolean Returns boolean FALSE if the phone number is not valid.
*/
function valid_ca_phone_number($phonenumber) {
$phonenumber = trim($phonenumber);
// define regular expression
$regex = '/
\D* # ignore non-digits
(\d*) # an optional 1
\D* # optional separator
[2-9][0-8]\d # area code (Allowed range of [2-9] for the first digit, [0-8] for the second, and [0-9] for the third digit)
\D* # optional separator
[2-9]\d{2} # 3-digit prefix (cannot start with 0 or 1)
\D* # optional separator
\d{4} # 4-digit line number
\D* # optional separator
\d* # optional extension
\D* # ignore trailing non-digits
/x';
// return true if valid, false otherwise
$result = preg_match($regex, $phonenumber, $matches);
return ($result && ($matches[1] == '' || $matches[1] == '1'));
}
/**
* Convert a valid North American phone number into standard (444) 867-5309 x1234 format
*
* @param $phonenumber must be a valid ten-digit number (with optional extension)
*
*/
function format_ca_phone_number($phonenumber, $field) {
// define regular expression
$regex = '/
\D* # ignore non-digits
(\d*) # an optional 1
\D* # optional separator
([2-9][0-8]\d) # area code (Allowed range of [2-9] for the first digit, [0-8] for the second, and [0-9] for the third digit)
\D* # optional separator
([2-9]\d{2}) # 3-digit prefix (cannot start with 0 or 1)
\D* # optional separator
(\d{4}) # 4-digit line number
\D* # optional separator
(\d*) # optional extension
\D* # ignore trailing non-digits
/x';
// get digits of phone number
preg_match($regex, $phonenumber, $matches);
$separator = isset($field['ca_phone_separator']) ? $field['ca_phone_separator'] : '-';
// construct ten-digit phone number
$phonenumber =
( $field['ca_phone_parentheses'] ?
'(' . $matches[2] . ') ' :
$matches[2] . $separator ) .
$matches[3] . $separator . $matches[4];
// Optional extension
if ($matches[5] != '') {
$phonenumber .= ' x' . $matches[5];
}
if ($field['phone_country_code']) {
// This condition check is pointless.
if ($matches[1] != '1') {
$phonenumber = '1' . ' ' . $phonenumber;
}
}
return $phonenumber;
}

View File

@@ -0,0 +1,51 @@
<?php
/**
* @file
* CCK Field for Switzerland phone numbers.
*/
define('PHONE_CH_REGEX', "%(\+41|0|0041)([2-9]\d{8})$%");
function phone_ch_metadata() {
// These strings are translated using t() on output.
return array(
'error' => '"%value" is not a valid Swiss phone number<br>Swiss phone numbers should only contain numbers and spaces and be like 099 999 99 99',
);
}
/**
* Verification for private/standr switzerland Phone Numbers (E.164/2002).
* According to http://en.wikipedia.org/wiki/Telephone_numbers_in_Switzerland#After_2002
* (Released 2002)
*
* @param string $phonenumber
* @return boolean Returns boolean FALSE if the phone number is not valid.
*/
function valid_ch_phone_number($phonenumber) {
$phonenumber = str_replace(array(' ','-','.','/','(',')'), '', $phonenumber);
$match =array();
$result = (bool) preg_match(PHONE_CH_REGEX, $phonenumber, $match);
return $result;
}
/**
* Formatting for Switzerland Phone Numbers.
*
* @param string $phonenumber
* @return string Returns a string containting the phone number with some formatting.
*/
function format_ch_phone_number($phonenumber, $field = FALSE) {
$phone = str_replace(array(' ','-','.','/','(',')'), '', $phonenumber);
$matches =array();
if (preg_match(PHONE_CH_REGEX, $phone, $matches) != 1) {
return $phonenumber; // not a switzerland phone number
}
$value =($field && $field['phone_country_code'] ? '+41 (0)' : '0') .
substr($matches[2],0,2).
' '.substr($matches[2],2,3).
' '.substr($matches[2],5,2).
' '.substr($matches[2],7);
return $value;
}

View File

@@ -0,0 +1,49 @@
<?php
/**
* @file
* CCK Field for Chili phone numbers.
*/
function phone_cl_metadata() {
// These strings are translated using t() on output.
return array(
'error' => '"%value" is not a valid Chilean mobile phone number<br>Chili phone numbers should only ...',
);
}
/**
* Verifies that $phonenumber is valid
*
* @param string $phonenumber
* @return boolean Returns boolean FALSE if the phone number is not valid.
*/
function valid_cl_phone_number($phonenumber) {
// define regular expression
$regex = "/^((\(\d{3}\) ?)|(\d{3}-)|(\(\d{2}\) ?)|(\d{2}-)|(\(\d{1}\) ?)|(\d{1}-))?\d{3}-(\d{3}|\d{4})$/i";
// return true if valid, false otherwise
return (bool) preg_match($regex, $phonenumber);
}
/**
* Formatting for Chili Phone Numbers.
*
* @param string $phonenumber
* @return string Returns a string containting the phone number with some formatting.
*/
function format_cl_phone_number($phonenumber, $field) {
//$phonenumber = trim($phonenumber);
// do some formatting on the phone number
/* ==> to be done ==> add the country code
if ($field['phone_country_code']) {
if ($matches[1] != "+39") {
$phonenumber = "+39" . " " . $phonenumber;
}
}
*/
return $phonenumber;
}

View File

@@ -0,0 +1,41 @@
<?php
/**
* @file
* CCK Field for China phone numbers.
*/
function phone_cn_metadata() {
// These strings are translated using t() on output.
return array(
'error' => '"%value" is not a valid Chinese phone number!<br>Chinese phone numbers should ...',
);
}
/**
* Verifies that $phonenumber is a valid Chinese phone number
*
* @param string $phonenumber
* @return boolean Returns boolean FALSE if the phone number is not valid.
*/
function valid_cn_phone_number($phonenumber) {
$phonenumber = trim($phonenumber);
// define regular expression
$regex = '/^(\+86|86)?( |-)?([0-9]{11}|([0-9]{3,4}(\-|\.| )[0-9]{3,8})|[0-9]{2}( |\-)[0-9]{4}[ ][0-9]{4}|[0-9]{2}\.[0-9]{2}\.[0-9]{2}\.[0-9]{2}\.[0-9]{2})$/';
// return true if valid, false otherwise
return (bool) preg_match($regex, $phonenumber);
}
/**
* Convert a valid Chinese phone number into standard ... format
*
* @param $phonenumber must be a valid number (with optional international prefix)
*
*/
function format_cn_phone_number($phonenumber, $field) {
return $phonenumber;
}

View File

@@ -0,0 +1,73 @@
<?php
/**
* @file
* CCK Field for Costa Rican phone numbers.
*/
function phone_cr_metadata() {
// These strings are translated using t() on output.
return array(
'error' => '"%value" is not a valid Costa Rican phone number!<br>Costa Rican phone numbers should contain only numbers and spaces be like 99 99 99 99 with an optional prefix of "+506" or "00506".',
);
}
/**
* Verifies that $phonenumber is a valid eight-digit Costa Rican phone number
*
* @param string $phonenumber
* @return boolean Returns boolean FALSE if the phone number is not valid.
*/
function valid_cr_phone_number($phonenumber) {
//$phonenumber = trim($phonenumber);
// define regular expression
$regex = "/(00)?[\s|-]?((\+)?[\s|-]?[0-9]{3})?[\s|-]?([0-9]{2})[\s|-]?([0-9]{2})[\s|-]?([0-9]{2})[\s|-]?([0-9]{2})[\s|-]?/";
// return true if valid, false otherwise
return (bool) preg_match($regex, $phonenumber);
}
/**
* Convert a valid Costa Rican phone number into standard (+506) 5555 55 55 format
*
* @param $phonenumber must be a valid eight-digit number (with optional international prefix)
*
*/
/*
Accepts:
+506 88798857
+506 88-79-88-57
00506 88798857
00506 88-79-88-57
Rejects:
+506 8 8798857
+506 8 8-79-88-57
00506 8 8798857
00506 8 8-79-88-57 */
function format_cr_phone_number($phonenumber, $field = FALSE) {
// define regular expression
$regex = "/(00)?[\s|-]?((\+)?[\s|-]?[0-9]{3})?[\s|-]?([0-9]{2})[\s|-]?([0-9]{2})[\s|-]?([0-9]{2})[\s|-]?([0-9]{2})[\s|-]?/";
// get digits of phone number
//dprint_r($matches);
preg_match($regex, $phonenumber, $matches);
// construct eight-digit phone number
//dprint_r($matches);
$phonenumber = $matches[4] . '-' . $matches[5] . '-' . $matches[6] . '-' . $matches[7];
if($matches[2]){
if($matches[1])
$phonenumber = "+" . $matches[2] . " " . $phonenumber;
else
$phonenumber = $matches[2] . " " . $phonenumber;
}
return $phonenumber;
}

View File

@@ -0,0 +1,54 @@
<?php
/**
* @file
* CCK Field for Czech phone numbers.
*/
function phone_cs_metadata() {
// These strings are translated using t() on output.
return array(
'error' => '"%value" is not a valid Czech phone number!<br>Czech phone numbers should contain only numbers and spaces be like 999 999 999 with an optional prefix of "+420" or "00420".',
);
}
/**
* Verifies that $phonenumber is a valid nine-digit Czech phone number
*
* @param string $phonenumber
* @return boolean Returns boolean FALSE if the phone number is not valid.
*/
function valid_cs_phone_number($phonenumber) {
$phonenumber = trim($phonenumber);
// define regular expression
$regex = '/^((?:\+|00)420)? ?(\d{3}) ?(\d{3}) ?(\d{3})$/';
// return true if valid, false otherwise
return (bool) preg_match($regex, $phonenumber);
}
/**
* Convert a valid Czech phone number into standard (+420) 999 999 999 format
*
* @param $phonenumber must be a valid nine-digit number (with optional international prefix)
*
*/
function format_cs_phone_number($phonenumber, $field) {
// define regular expression
$regex = '/^((?:\+|00)420)? ?(\d{3}) ?(\d{3}) ?(\d{3})$/';
// get digits of phone number
preg_match($regex, $phonenumber, $matches);
if ($field['phone_country_code']) {
$phonenumber = '+420' . ' ' . $matches[2] .' '. $matches[3] .' '. $matches[4];
}
else {
$phonenumber = $matches[2] .' '. $matches[3] .' '. $matches[4];
}
return $phonenumber;
}

View File

@@ -0,0 +1,143 @@
<?php
/* 2009/10/24, Ahmad Gharbeia: initial release
General phone number format is +20 (#[#]) #######[#]
currently (10/2009) only Greater Cairo (including all of Giza) has 8 digits:
Regional area codes:
??????? ?????? 2
?????????? 3
????????? 13
?????? ?? ????? 15
??????? 4
??????? 45
????? 46
???????? 47
???????? 48
???????? 5
??????? 55
????? 57
?????? 62
??????????? 64
??????? 65
??????? 66
?????? 68
???? ????? 69
??? ???? 82
?????? 84
?????? 86
????? 88
?????? ?????? 92
????? 93
?????? 95
??? 96
????? 97
mobile network operators' area codes:
Mobinil: 12, 16
Vodafone: 10, 19
Etisalat: 11, 18
**/
define('AREA_CODE_REGEX', "
(
1(3|5)
|3
|4(5|6|7|8|)
|5(5|7|)
|6(2|4|5|6|8|9)
|8(2|4|6|8)
|9(2|3|5|6|7)
)
");
define('MOBILE_CODE_REGEX', "1(0|2|1|6|8|9)"); //area codes 10, 11, 12, 16, 18, or 19
define('TELEPHONE_REGEX', "
(\+20)\s # optional countrycode optionally followed by a space
(
\(2\)\s(2|3)\d{3}\s\d{4} # 8-digit numbers begining with 2 or 3 (Greater Cairo: Cairo and Giza, both having area code = 2)
|
\(" . AREA_CODE_REGEX . "\)\s\d{3}\s\d{4} # all other areas' numbers have 7 digits. Checks for correct area codes
|
\(" . MOBILE_CODE_REGEX . "\)\s\d{3}\s\d{4} # mobile operators' networks' area codes; followed by 7 digits
)
(\s\#\s\d+)? # optional extension number shown with a hash divider
");
function phone_eg_metadata() {
// These strings are translated using t() on output.
return array(
'error' => '"%value" is not a valid phone number in Egypt. Telephone numbers in Egypt have the format +20 (#[#]) 1234567[8], where the digts between ( ) is the area or network code, without a leading zero; and digits between [ ] are optional',
);
}#end function phone_eg_metadata;
function valid_eg_phone_number($phonenumber) {
/*
accepts:
properly formatted: [+20][ ][(]#[#][)][ ]1234[ ]567[#]
common: [(][0#[#]][)][ ]123[ ]456[#]
area code could be within paranthises and|or prefixed with 0
*/
$regex = "/^ # the same as the model regex above, but with elements made optional
(\+20)?\s? # country code, with following space being optional
(
(\(0?2\)|0?2)\s?(2|3)\d{3}\s?\d{4} # Greater Cairo, with leading optional zeros and optional braces around the area code
|
(\(0?" . AREA_CODE_REGEX . "\)|0?" . AREA_CODE_REGEX . ")\s?\d{3}\s?\d{4} # other areas, with optional leading zeros and braces
|
(\(0?" . MOBILE_CODE_REGEX . "\)|0?" . MOBILE_CODE_REGEX . ")\s?\d{3}\s?\d{4} # mobiles, with optional leading zeros and braces
)
(\s?\#\s?\d+)? # extension
$/x";
return (bool) preg_match($regex, $phonenumber);
}#end function valid_eg_phone_number;
function format_eg_phone_number($phonenumber, $field) {
if (preg_match("/^" . TELEPHONE_REGEX . "$/x", $phonenumber)) { //already in proper format
return $phonenumber;
}
else { //remove country code, zeros, and braces
$phonenumber = preg_replace("/(^(\+20)?\s?|\(0?|\)|^0?)/", '', $phonenumber);
}
//If there are some spaces in the number assume some level of preformatting
if (preg_match("/ /", $phonenumber)) {
$regex = "/^
(
(\d{1,2}) # area code
\s* # ignore required separator
(\d{3,4}) # 4 digits in case of Greater Cairo
\s*
(\d{4})
)
((\s*\#)?(\d*))? # extension
$/x";
preg_match($regex, $phonenumber, $matches);
$area = $matches[2];
$number = $matches[3] . ' ' . $matches[4];
$extension = $matches[7];
}
else { //no spaces?, then apply some guessing
$regex = "/^ # order is important in this one
(
(\d)(\d{4})(\d{4}) # 2 area code, followed by 8 digits begining with 2 or 3: Greater Cairo
|
(\d{1,2})(\d{3})(\d{4}) # 1 or 2-digit area code followed by 7 digits: regional or mobile
)
((\s*\#)?(\d*))?
$/x";
preg_match($regex, $phonenumber, $matches);
$area = $matches[2];
$number = $matches[3] . ' ' . $matches[4];
$extension = $matches[5];
}
return '+20 (' . $area . ') ' . $number . (empty($extension) ? '' : " #$extension");
}#end function format_eg_phone_number;

View File

@@ -0,0 +1,49 @@
<?php
/**
* @file
* CCK Field for Greek phone numbers.
*/
function phone_el_metadata() {
// These strings are translated using t() on output.
return array(
'error' => '"%value" is not a valid Greek phone number<br>Greek phone numbers should only ...',
);
}
/**
* Verifies that $phonenumber is valid
*
* @param string $phonenumber
* @return boolean Returns boolean FALSE if the phone number is not valid.
*/
function valid_el_phone_number($phonenumber) {
// define regular expression
$regex = "/^(\+30)?[ ]?([0-9]{3,4}(\/|-| )?[0-9]{6,7})$/i";
// return true if valid, false otherwise
return (bool) preg_match($regex, $phonenumber);
}
/**
* Formatting for Greek Phone Numbers.
*
* @param string $phonenumber
* @return string Returns a string containting the phone number with some formatting.
*/
function format_el_phone_number($phonenumber, $field) {
//$phonenumber = trim($phonenumber);
// do some formatting on the phone number
$phonenumber = str_replace("[ -]", "", $phonenumber);
if ($field['phone_country_code']) {
if ($matches[1] != "+30") {
$phonenumber = "+30" . " " . $phonenumber;
}
}
return $phonenumber;
}

View File

@@ -0,0 +1,73 @@
<?php
/**
* @file
* CCK Field for Spanish phone numbers.
*/
function phone_es_metadata() {
// These strings are translated using t() on output.
return array(
'error' => '"%value" is not a valid Spanish phone number<br>Spanish phone numbers should only contains numbers and spaces and be like 999 999 999',
);
}
/**
* Verifies that $phonenumber is a valid nine-digit Spanish phone number
*
* @param string $phonenumber
* @return boolean Returns boolean FALSE if the phone number is not valid.
*/
function valid_es_phone_number($phonenumber) {
$phonenumber = trim($phonenumber);
// define regular expression
//$regex = "/
// \D* # optional separator
// [69]\d{2} # first group of numbers
// \D* # optional separator
// \d{3} # second group
// \D* # optional separator
// \d{3} # third group
// \D* # ignore trailing non-digits
// $/x";
$regex = '/^[0-9]{2,3}-? ?[0-9]{6,7}$/';
// return true if valid, false otherwise
return (bool) preg_match($regex, $phonenumber);
}
/**
* Convert a valid Spanish phone number into standard (+34) 916 555 777 format
*
* @param $phonenumber must be a valid nine-digit number (with optional international prefix)
*
*/
function format_es_phone_number($phonenumber, $field = FALSE) {
// define regular expression
//$regex = "/
// \D* # optional separator
// ([69]\d{2}) # first group of numbers
// \D* # optional separator
// (\d{3}) # second group
// \D* # optional separator
// (\d{3}) # third group
// \D* # ignore trailing non-digits
// $/x";
$regex = '/^[0-9]{2,3}-? ?[0-9]{6,7}$/';
// get digits of phone number
preg_match($regex, $phonenumber, $matches);
// construct ten-digit phone number
$phonenumber = $matches[1] . ' ' . $matches[2] . ' ' . $matches[3];
return $phonenumber;
}

View File

@@ -0,0 +1,46 @@
<?php
/**
* @file
* CCK Field for French phone numbers.
*/
define('PHONE_FR_REGEX', '/(\+33|0)([1-9]\d{8}|85\d{7}|87[0-57-9]\d{6})$/');
function phone_fr_metadata() {
// These strings are translated using t() on output.
return array(
'error' => '"%value" is not a valid French phone number<br>French phone numbers should only contain numbers and spaces and be like 99 99 99 99 99',
);
}
/**
* Verification for French Phone Numbers.
* According to http://www.itu.int/itudoc/itu-t/number/f/fra/70680.html
* (Released 2006/01/26, retrieved 2008/08/12)
*
* @param string $phonenumber
* @return boolean Returns boolean FALSE if the phone number is not valid.
*/
function valid_fr_phone_number($phonenumber) {
//$phonenumber = trim($phonenumber);
$phonenumber = str_replace(array(' ','-','(',')'), '', $phonenumber);
return (bool) preg_match(PHONE_FR_REGEX, $phonenumber);
}
/**
* Formatting for French Phone Numbers.
*
* @param string $phonenumber
* @return string Returns a string containting the phone number with some formatting.
*/
function format_fr_phone_number($phonenumber, $field = FALSE) {
$phone = str_replace(array(' ','-','(',')'), '', $phonenumber);
if (preg_match(PHONE_FR_REGEX, $phone, $matches) != 1) {
return $phonenumber; // not a french phone number
}
return ($field && $field['phone_country_code'] ? '+33 ' : '0') . $matches[2];
}

View File

@@ -0,0 +1,143 @@
<?php
/**
* @file
* CCK Field for British phone numbers.
*/
function phone_gb_metadata() {
// These strings are translated using t() on output.
return array(
'error' => '"%value" is not a valid British (UK) phone number<br>British Phone numbers should .... ',
);
}
/**
* Verifies that $phonenumber is a valid eleven-digit United Kingdom phone number
*
* Regular expression adapted from Amos Hurd's regex at RegExLib.com
*
* @param string $phonenumber
* @return boolean Returns boolean FALSE if the phone number is not valid.
*/
function valid_gb_phone_number($phonenumber) {
/*
Accepts:
+441970123456
+44(0)1970123456
+44 1970 123 456
+44 (0)1970 123 456
(01970) 123456 #0001
Rejects:
(+441970)123456
+44(1970)123456
+44 01970 123 456
(0197) 0123456 #01
*/
$regex = "/
(
(^\+44\s?(\(0\))?\d{4}|^\(?0\d{4}\)?){1}\s?\d{3}\s?\d{3} # 4 digit area code with optional +44 internationalisation or not, optional spaces and brackets.
|
(^\+44\s?(\(0\))?\d{3}|^\(?0\d{3}\)?){1}\s?\d{3}\s?\d{4} # 3 digit area code with optional +44 internationalisation or not, optional spaces and brackets.
|
(^\+44\s?(\(0\))?\d{2}|^\(?0\d{2}\)?){1}\s?\d{4}\s?\d{4} # 2 digit area code with optional +44 internationalisation or not, optional spaces and brackets.
|
(^\+44\s?(\(0\))?\d{1}|^\(?0\d{1}\)?){1}\s?\d{5}\s?\d{5} # 1 digit area code with optional +44 internationalisation or not, optional spaces and brackets.
)
(\s?\#\d*)? # optional extension number shown with a hash divider
/x";
if (!preg_match($regex, $phonenumber)) {
return FALSE;
}
else
{
return TRUE;
}
}
/**
* Convert a valid United Kingdom phone number into standard +44 (0)1970 123 456 #001 international format
*
* @param $phonenumber must be a valid eleven-digit number (with optional extension)
*
*/
function format_gb_phone_number($phonenumber, $field = FALSE) {
$area = $number = $extension = '';
//If we already have the formatting we want just return
if (preg_match(
"/
(
\+44\s\(0\)\d{4}\s\d{3}\s\d{3} # 4 digit area code
|
\+44\s\(0\)\d{3}\s\d{3}\s\d{4} # 3 digit area code
|
\+44\s\(0\)\d{2}\s\d{4}\s\d{4} # 2 digit area code
)
(\s\#\d*)?
/",$phonenumber)) {
return $phonenumber;
}
else {
//Simplify to 10 digit number and clean up ready for international reformat.
$phonenumber = preg_replace("/^(\+44)?\s?(\(?0\)?)?/","",$phonenumber);
$phonenumber = preg_replace("/\(/","",$phonenumber);
$phonenumber = preg_replace("/\(0/","",$phonenumber);
$phonenumber = preg_replace("/\)/","",$phonenumber);
//If there are some spaces in the number assume some level of preformatting
if(preg_match("/ /",$phonenumber)) {
$regex = "/
# 4 digit area code.
(
(\d{4}) # capture 4 digit area code
\s+ # ignore required separator to make a distinction with other area codes
(\d{3}) # capture first set of numbers in the local number
\s* # ignore optional separator
(\d{3}) # capture second set of numbers in the local number
|
# 3 digit area code.
(\d{3}) # capture 3 digit area code
\s+ # ignore required seperator
(\d{3}) # capture first set of numbers in the local number
\s* # ignore possible boundary
(\d{4}) # capture second set of numbers in the local number
|
# 2 digit area code.
(\d{2}) # capture 2 digit area code
\s+ # ignore required boundary to make a distinction with other area codes
(\d{4}) # capture first set of numbers in the local number
\s* # ignore possible boundary
(\d{4}) # capture second set of numbers in the local number
)
# capture the optional extension number
(\s*\#)?
(\d{4}|\d{3})?
/x";
preg_match($regex, $phonenumber, $matches);
$area = $matches[2].$matches[5].$matches[8];
$number = $matches[3].$matches[6].$matches[9].' '.$matches[4].$matches[7].$matches[10];
$extension = $matches[12];
}
//If there are no spaces in the number assume 4 digit area code.
else {
preg_match("/(\d{4})(\d{3})(\d{3})\#?(\d*)?/",$phonenumber, $matches);
$area = $matches[1];
$number = $matches[2].' '.$matches[3];
$extension = $matches[4];
}
if ($field['phone_country_code']) {
$phonenumber = '+44 (0)'.$area.' '.$number;
}
else {
$phonenumber = '0'.$area.' '.$number;
}
$phonenumber .= (empty($extension))?'':" #$extension";
}
return $phonenumber;
}

View File

@@ -0,0 +1,52 @@
<?php
/**
* @file
* CCK Field for Hungarian phone numbers.
*/
define('PHONE_HU_REGEX', "/^(\+36|06|)[\s.-]?([0-9]{1,2})[\s.-]?([0-9]{2,3})[\s.-]?([0-9]{2,4})$/");
function phone_hu_metadata() {
// These strings are translated using t() on output.
return array(
'error' => '"%value" is not a valid Hungarian phone number!<br>Hungarian phone numbers should contain only numbers and spaces be like 70 999 9999 with an optional prefix of "+36" or "06".',
);
}
/**
* Verifies that $phonenumber is a valid nine-digit Hungarian phone number
*
* @param string $phonenumber
* @return boolean Returns boolean FALSE if the phone number is not valid.
*/
function valid_hu_phone_number($phonenumber) {
$phonenumber = trim($phonenumber);
// return true if valid, false otherwise
return (bool) preg_match(PHONE_HU_REGEX, $phonenumber);
}
/**
* Convert a valid Hungarian phone number into standard (+36) ..... format
*
* @param $phonenumber must be a valid nine-digit number (with optional international prefix)
*
*/
function format_hu_phone_number($phonenumber, $field = FALSE) {
$phonenumber = trim($phonenumber);
// get digits of phone number
preg_match(PHONE_HU_REGEX, $phonenumber, $matches);
$formatedphone = '';
if ($field && $field['phone_country_code']) {
$formatedphone .= '+36 ';
}
// construct ten-digit phone number
$formatedphone .= $matches[2] . ' ' . $matches[3] . ' ' . $matches[4];
return $formatedphone;
}

View File

@@ -0,0 +1,108 @@
<?php
//drived from au module and manipulated by Moshe Beeri, email: moshe.beeri (at-shetrudel) google mail
/**
* @file
* CCK Field for Isreali phone numbers.
*/
function phone_il_metadata() {
return array(
'error' => '"%value" is not a valid Israeli phone number',
);
}
/**
* Verification for Israel Phone Numbers.
*
* @param string $phonenumber
* @return boolean Returns boolean FALSE if the phone number is not valid.
*/
function valid_il_phone_number($phonenumber) {
//$phonenumber = trim($phonenumber);
// strip formatting chars
$phonenumber = preg_replace('/[\-() ]/', '', $phonenumber);
// strip optional '+972' or '0' prefixes
$phonenumber = preg_replace('/^(\+972)/', '', $phonenumber);
//$rules[] = array("Prefix","Minimum length","Maximum length");
//http://he.wikipedia.org/wiki/%D7%A7%D7%99%D7%93%D7%95%D7%9E%D7%AA_%D7%98%D7%9C%D7%A4%D7%95%D7%9F
$rules[] = array("02", 7, 10);
$rules[] = array("03", 7, 10);
$rules[] = array("04", 7, 10);
$rules[] = array("08", 7, 10);
$rules[] = array("09", 7, 10);
$rules[] = array("072", 7, 10);
$rules[] = array("073", 7, 10);
$rules[] = array("074", 7, 10);
$rules[] = array("076", 7, 10);
$rules[] = array("077", 7, 10);
$rules[] = array("078", 7, 10);
$rules[] = array("050", 7, 10);
$rules[] = array("052", 7, 10);
$rules[] = array("054", 7, 10);
$rules[] = array("057", 7, 10);
$rules[] = array("1800", 6, 10);
$rules[] = array("1801", 6, 10);
$rules[] = array("1700", 6, 10);
foreach ($rules as $rule) {
if (preg_match('/^'.$rule[0].'/', $phonenumber) && strlen($phonenumber) >= $rule[1] && strlen($phonenumber) <= $rule[2]) {
return TRUE;
}
}
return FALSE;
}
/**
* Formatting for Israeli Phone Numbers. Based upon ITU-T E.123 (but let's not get too crazy)
*
* @param string $phonenumber
* @return string Returns a string containing the phone number with some formatting.
*/
function format_il_phone_number($phonenumber) {
$prefix = '';
$extension = '';
// strip old formatting chars
$phonenumber = preg_replace('/[\-() ]/', '', $phonenumber);
/*
* strip and save the +9726 prefix if found
*/
if (preg_match('/^\+972/', $phonenumber, $match)) {
$prefix = '+972 ';
$phonenumber = str_replace('+972', '', $phonenumber);
}
/*
* 9 phones digit numbers
* Eg. 03 9999 999
*/
if (preg_match('/^([0-9]{2})([0-9]{4})([0-9]{3})$/', $phonenumber, $match)) {
return $prefix . $match[1] . ' ' . $match[2] . ' ' . $match[3] . $extension;
}
/*
* 10 digit numbers
* Eg. 1800 999 999
*/
if (preg_match('/^([0-9]{4})([0-9]{3})([0-9]{3})$/', $phonenumber, $match)) {
return $prefix . $match[1] . ' ' . $match[2] . ' ' . $match[3] . $extension;
}
/*
* cell phone
* Eg. 054 9999 999
*/
if (preg_match('/^([0-9]{3})([0-9]{4})([0-9]{3})$/', $phonenumber, $match)) {
return $prefix . $match[1] . ' ' . $match[2] . ' ' . $match[3] . $extension;
}
// default
return $prefix . $phonenumber . $extension;
}

View File

@@ -0,0 +1,354 @@
<?php
function phone_int_metadata() {
// These strings are translated using t() on output.
return array(
'error' => '"%value" is not a valid Italian phone number<br>Italian phone numbers should only ...',
);
}
/**
* Verifies that $phonenumber is a valid international phone number as per ITU or,
* if a default country code is specified, a valid subscriber number.
*
* @see http://www.itu.int/rec/T-REC-E.123/en
*
* @param $phonenumber
* International phone number to validate
* @return
* TRUE if valid, FALSE if otherwise.
*/
function valid_int_phone_number($phonenumber) {
$phonenumber = trim($phonenumber);
if ($phonenumber === '') {
return FALSE;
}
$phonenumber = _normalize_country_code($phonenumber);
$base_phonenumber = str_replace(array('.', '(', ')', '[', ']', '-', '+', ' '), '', $phonenumber);
if (!isset($field['phone_int_max_length'])) {
$field['phone_int_max_length'] = 15;
}
if (strlen($base_phonenumber) > $field['phone_int_max_length']) {
$error = t('Invalid international phone number: Phone number is too long; international phone numbers are limited to 15 digits.');
return FALSE;
}
// Check if digits are used in the base_phonenumber
if (!ctype_digit($base_phonenumber)) {
$error = t('Invalid international phone number: Phone number contains invalid characters; only allowed characters are numbers and punctuation.');
return FALSE;
}
// Extract country code and see if it's correct:
preg_match('/^\+(\d+)/', $phonenumber, $matches);
$cc = $matches[1];
if (strlen($cc) > 3) {
$error = array(
t('Invalid international phone number: Country code "+%cc" is too long; valid country codes are three digits or less.'),
array('%cc' => $cc)
);
return FALSE;
}
//drupal_set_message('langue cc = ' . $cc, 'error');
// TODO: Check if parentheses/brackets add up.
// TODO: Validate the number against the country rules.
// For now, validate only against a limited number of countries.
$countrycode = phone_country_code_convert($cc);
//drupal_set_message('langue countrycode = ' . $countrycode, 'error');
if (!empty($countrycode)) {
$valid_phone_function = 'valid_'. $countrycode . '_phone_number';
module_load_include('inc', 'phone', 'phone.'. $countrycode);
if (function_exists($valid_phone_function)) {
return $valid_phone_function($phonenumber, $field);
}
else {
return TRUE;
}
}
return FALSE;
}
/**
* Formats $phonenumber into the standard representation of international
* numbers as per E.123.
*
* @param $phonenumber
* International phone number to format
* @return
* Formatted international phone number
*/
function format_int_phone_number($phonenumber, $field = array()) {
$phonenumber = trim($phonenumber);
if ($phonenumber === '') {
return '';
}
$phonenumber = _normalize_country_code($phonenumber, $field);
$bits = preg_split('/[.()\[\]\- ]/', $phonenumber, -1, PREG_SPLIT_NO_EMPTY);
// $bits[0] is the country code WITH a plus sign.
if (isset($bits[1])) {
// This is the first non-CC segment, so it could have the NDN.
switch ($bits[1][0]) {
case 0:
$bits[1] = substr($bits[1], 1);
break;
}
switch ($bits[1]) {
case 0:
case 7:
case 8:
array_splice($bits, 1, 1);
break;
}
}
return implode(' ', $bits);
}
/**
* Adds a country code to a phone number if necessary.
*
* @param $phonenumber
* International or local phone number to format
* @return
* International phone number with country code
*/
function _normalize_country_code($phonenumber, $field = array()) {
if ($phonenumber[0] !== '+') {
$cc = isset($field['phone_default_country_code']) ? $field['phone_default_country_code'] : '1';
return "+$cc $phonenumber";
}
return $phonenumber;
}
/**
* Returns the country code in the desired format.
*
* @todo Fill in the rest of the country code values.
*
* @param $code
* Country code to convert (either numeric or 2-letter abbreviation)
* @param $input_type
* Type of country code to convert (either numeric or 2-letter abbreviation)
* @return
* Converted country code
*/
function phone_country_code_convert($code, $input_type = 'digits') {
static $codes;
if (!$codes) {
$codes = array(
'1' => 'ca',
'1' => 'us',
'7' => 'ru',
'20' => 'eg',
'27' => 'za',
'30' => 'gr',
'31' => 'nl',
'32' => 'be',
'33' => 'fr',
'34' => 'es',
'36' => 'hu',
'39' => 'it',
'39' => 'va',
'40' => 'ro',
'41' => 'ch',
'43' => 'at',
'44' => 'gb',
'45' => 'dk',
'46' => 'se',
'47' => 'no',
'48' => 'pl',
'49' => 'de',
'51' => 'pe',
'52' => 'mx',
'53' => 'cu',
'54' => 'ar',
'55' => 'br',
'56' => 'cl',
'57' => 'co',
'58' => 've',
'60' => 'my',
'61' => 'au',
'61' => 'cc',
'61' => 'cx',
'62' => 'id',
'63' => 'ph',
'64' => 'nz',
'65' => 'sg',
'66' => 'th',
'81' => 'jp',
'82' => 'kr',
'84' => 'vn',
'86' => 'cn',
'90' => 'tr',
'91' => 'in',
'92' => 'pk',
'93' => 'af',
'94' => 'lk',
'95' => 'mm',
'98' => 'ir',
'212' => 'ma',
'213' => 'dz',
'216' => 'tn',
'218' => 'ly',
'220' => 'gm',
'221' => 'sn',
'222' => 'mr',
'223' => 'ml',
'224' => 'gn',
'225' => 'ci',
'226' => 'bf',
'227' => 'ne',
'228' => 'tg',
'229' => 'bj',
'230' => 'mu',
'231' => 'lr',
'232' => 'sl',
'233' => 'gh',
'234' => 'ng',
'235' => 'td',
'236' => 'cf',
'237' => 'cm',
'238' => 'cv',
'239' => 'st',
'240' => 'gq',
'241' => 'ga',
'242' => 'cg',
'243' => 'cd',
'244' => 'ao',
'245' => 'gw',
'246' => 'io',
'248' => 'sc',
'249' => 'sd',
'250' => 'rw',
'251' => 'et',
'252' => 'so',
'253' => 'dj',
'254' => 'ke',
'255' => 'tz',
'256' => 'ug',
'257' => 'bi',
'258' => 'mz',
'260' => 'zm',
'261' => 'mg',
'263' => 'zw',
'264' => 'na',
'265' => 'mw',
'266' => 'ls',
'267' => 'bw',
'268' => 'sz',
'269' => 'km',
'269' => 'yt',
'290' => 'sh',
'291' => 'er',
'297' => 'aw',
'298' => 'fo',
'299' => 'gl',
'350' => 'gi',
'351' => 'pt',
'352' => 'lu',
'353' => 'ie',
'354' => 'is',
'355' => 'al',
'356' => 'mt',
'357' => 'cy',
'358' => 'fi',
'359' => 'bg',
'370' => 'lt',
'371' => 'lv',
'372' => 'ee',
'373' => 'md',
'374' => 'am',
'375' => 'by',
'376' => 'ad',
'377' => 'mc',
'378' => 'sm',
'380' => 'ua',
'381' => 'rs',
'382' => 'me',
'385' => 'hr',
'386' => 'si',
'387' => 'ba',
'389' => 'mk',
'420' => 'cz',
'421' => 'sk',
'423' => 'li',
'500' => 'fk',
'501' => 'bz',
'502' => 'gt',
'503' => 'sv',
'504' => 'hn',
'505' => 'ni',
'506' => 'cr',
'507' => 'pa',
'508' => 'pm',
'509' => 'ht',
'590' => 'gp',
'591' => 'bo',
'592' => 'gy',
'593' => 'ec',
'594' => 'gf',
'595' => 'py',
'596' => 'mq',
'597' => 'sr',
'598' => 'uy',
'599' => 'an',
'670' => 'tp',
'672' => 'nf',
'673' => 'bn',
'674' => 'nr',
'675' => 'pg',
'676' => 'to',
'677' => 'sb',
'678' => 'vu',
'679' => 'fj',
'680' => 'pw',
'681' => 'wf',
'682' => 'ck',
'683' => 'nu',
'686' => 'ki',
'687' => 'nc',
'688' => 'tv',
'689' => 'pf',
'690' => 'tk',
'691' => 'fm',
'692' => 'mh',
'850' => 'kp',
'852' => 'hk',
'853' => 'mo',
'855' => 'kh',
'856' => 'la',
'880' => 'bd',
'886' => 'tw',
'960' => 'mv',
'961' => 'lb',
'962' => 'jo',
'963' => 'sy',
'964' => 'iq',
'965' => 'kw',
'966' => 'sa',
'967' => 'ye',
'968' => 'om',
'970' => 'ps',
'971' => 'ae',
'972' => 'il',
'973' => 'bh',
'974' => 'qa',
'975' => 'bt',
'976' => 'mn',
'977' => 'np',
'992' => 'tj',
'993' => 'tm',
'994' => 'az',
'995' => 'ge',
'996' => 'kg',
'998' => 'uz',
);
}
if ($input_type == 'alpha') {
$codes = array_flip($codes);
}
return isset($codes[$code]) ? $codes[$code] : FALSE;
}

View File

@@ -0,0 +1,49 @@
<?php
/**
* @file
* CCK Field for Italian phone numbers.
*/
function phone_it_metadata() {
// These strings are translated using t() on output.
return array(
'error' => '"%value" is not a valid Italian phone number<br>Italian phone numbers should only ...',
);
}
/**
* Verifies that $phonenumber is valid
*
* @param string $phonenumber
* @return boolean Returns boolean FALSE if the phone number is not valid.
*/
function valid_it_phone_number($phonenumber) {
// define regular expression
$regex = "/^(\+39)?[ ]?([0-9]{2,3}(\/|-| )?[0-9]{6,7})$/i";
// return true if valid, false otherwise
return (bool) preg_match($regex, $phonenumber);
}
/**
* Formatting for Italian Phone Numbers.
*
* @param string $phonenumber
* @return string Returns a string containting the phone number with some formatting.
*/
function format_it_phone_number($phonenumber, $field) {
//$phonenumber = trim($phonenumber);
// do some formatting on the phone number
$phonenumber = str_replace("[ -]", "", $phonenumber);
if ($field['phone_country_code']) {
if ($matches[1] != "+39") {
$phonenumber = "+39" . " " . $phonenumber;
}
}
return $phonenumber;
}

View File

@@ -0,0 +1,101 @@
<?php
/**
* This plugin is contributed by Untitled Web http://untitledstudios.com
* @author Rashad Majali <rashad.612@gmail.com> http://drupal.org/user/319686
* @file
* CCK Field for Jordanian phone numbers.
*/
function phone_jo_metadata(){
// These strings are translated using t() on output.
return array(
'error' => '"%value" is not a valid Jordanian phone number, Please check the spaces and dashes in your number.',
);
}
/**
* Verification for Jordanian Phone Numbers.
*
* @param string $phonenumber
* @return boolean Returns boolean FALSE if the phone number is not valid.
*/
function valid_jo_phone_number($phonenumber){
/**
Accepts:
Mobile numbers: (X refers to network code, it might be 7,8,9).
+9627X1234567
+962-7X1234567
+962 7X1234567
009627X1234567
00962-7X1234567
00962 7X1234567
962... accepted as well
07X1234567
Local area numbers: (X refers to region code, i.e. Amman[6], north [2], middle [5], south[3]).
+962X1234567
+962-X-1234567
+962X-1234567
+962 X 1234567
+962X 1234567
+962 X1234567
00962X1234567
00962-X-1234567
00962X-1234567
00962 X 1234567
00962X 1234567
00962 X1234567
962... accepted as well
0X1234567
0X-1234567
0X 1234567
Rejects:
Generally rejects any number without leading code.
starts with X instead of 0X
Mobile:
7X1234567
7 X1234567 and similar formats
+962 7 X1234567 and similar formats
Local:
X1234567
X-1234567
X 1234567 and similar formats
*/
$regex = "/(^(\+962|00962|962|0)[-\s]{0,1}[7]{1}[7-9]{1}[0-9]{7}$) | (^(\+962|00962|962|0)[-\s]{0,1}[2-6][-\s]{0,1}[0-9]{7}$)/x";
return (bool) preg_match($regex, $phonenumber);
}
/**
* Formatting for Jordanian Phone Numbers.
*
* @param string $phonenumber
* @return string Returns a string containting the phone number with some formatting.
*/
function format_jo_phone_number($phonenumber, $field = FALSE){
$phonenumber = trim($phonenumber);
$regex = "/(^(\+962|00962|962|0)[-\s]{0,1}[7]{1}[7-9]{1}[0-9]{7}$) | (^(\+962|00962|962|0)[-\s]{0,1}[2-6][-\s]{0,1}[0-9]{7}$)/x";
preg_match($regex, $phonenumber, $matches);
$phonenumber = preg_replace('/^(\+962|00962|962|0)|[-\s]/', '', $matches[0]);
return '+962'.$phonenumber;
}

View File

@@ -0,0 +1,87 @@
<?php
/**
* @file
* CCK Field for Dutch phone numbers.
*/
function phone_nl_metadata() {
// These strings are translated using t() on output.
return array(
'error' => '"%value" is not a valid Dutch phone number!<br>Dutch phone numbers should contain only numbers and spaces and - and be like 099-9999999 with an optional prefix of "+31".',
);
}
/**
* Verifies that $phonenumber is a valid ten-digit Dutch phone number with spaces and -
*
* Regular expression adapted from Nico Lubbers's regex at RegExLib.com
*
* @param string $phonenumber
* @return boolean Returns boolean FALSE if the phone number is not valid.
*/
function valid_nl_phone_number($phonenumber) {
//$phonenumber = trim($phonenumber);
/*
Accepts:
06-12345678
06 123 456 78
010-1234567
020 123 4567
0221-123456
0221 123 456
Rejects:
05-12345678
123-4567890
123 456 7890
*/
// define regular expression
$regex = '/
([0]{1}[6]{1}[-\s]+[1-9]{1}[\s]*([0-9]{1}[\s]*){7}) # Mobile phonenumber
|
([0]{1}[1-9]{1}[0-9]{2}[-\s]+[1-9]{1}[\s]*([0-9]{1}[\s]*){5}) # Phonenumber with 4 digit area code
|
([0]{1}[1-9]{1}[0-9]{1}[-\s]+[1-9]{1}[\s]*([0-9]{1}[\s]*){6}) # Phonenumber with 3 digit area code
/x';
// return true if valid, false otherwise
return (bool) preg_match($regex, $phonenumber);
}
/**
* Formatting for Dutch Phone Numbers into standard area-phonenumber or with extra country code +31 international format
*
* @param string $phonenumber
* @return string Returns a string containting the phone number with some formatting.
*/
function format_nl_phone_number($phonenumber, $field) {
$areacode = $localnumber = '';
// Mobile number
if (preg_match('/([0]{1}[6]{1}[-\s]+[1-9]{1}[\s]*([0-9]{1}[\s]*){7})/', $phonenumber)) {
preg_match('/([0]{1}[6]{1})[-\s]+([1-9]{1}[\s]*([0-9]{1}[\s]*){7})/', $phonenumber, $matches);
}
// Phonenumber with 4 digit area code
if (preg_match('/([0]{1}[1-9]{1}[0-9]{2}[-\s]+[1-9]{1}[\s]*([0-9]{1}[\s]*){5})/', $phonenumber)) {
preg_match('/([0]{1}[1-9]{1}[0-9]{2})[-\s]+([1-9]{1}[\s]*([0-9]{1}[\s]*){5})/', $phonenumber, $matches);
}
// Phonenumber with 3 digit area code
if (preg_match('/([0]{1}[1-9]{1}[0-9]{1}[-\s]+[1-9]{1}[\s]*([0-9]{1}[\s]*){6})/', $phonenumber)) {
preg_match('/([0]{1}[1-9]{1}[0-9]{1})[-\s]+([1-9]{1}[\s]*([0-9]{1}[\s]*){6})/', $phonenumber, $matches);
}
$areacode = $matches[1];
$localnumber = preg_replace('/ /', '', $matches[2]);
$phonenumber = $areacode. '-'. $localnumber;
// Add Country code if needed
if ($field['phone_country_code']) {
$areacode = preg_replace('/^0/', '', $areacode);
$phonenumber = '+31-'. $areacode. '-'. $localnumber;
}
return $phonenumber;
}

View File

@@ -0,0 +1,224 @@
<?php
/**
* @file
* CCK Field for New Zealand phone numbers.
*/
function phone_nz_metadata() {
// These strings are translated using t() on output.
return array(
'error' => '"%value" is not a valid New Zealand phone number!<br>New Zealand phone numbers should contain only numbers, spaces, brackets and "-". They should look like 04 123 4567 or can optionally omit the leading 0 and have a prefix of "+64".',
);
}
/**
* Verification for New Zealand Phone Numbers.
* As supplied by http://www.itu.int/itudoc/itu-t/number/n/nzl/76195_ww9.doc, April 2009
*
* @param string $phonenumber
* @return boolean returns boolean FALSE if the phone number is not valid.
*/
function valid_nz_phone_number($phonenumber) {
//$phonenumber = trim($phonenumber);
// strip formatting chars
$phonenumber = preg_replace('/[\-() ]/', '', $phonenumber);
// strip optional '+64' or '0' prefixes
$phonenumber = preg_replace('/^(\+64|0)/', '', $phonenumber);
//$rules[] = array("Prefix","Minimum length","Maximum length");
// special purpose service codes and numbers
/*// Enable if required
$rules[] = array('10', 3, 3);
$rules[] = array('12', 6, 7); // NZ Direct Service
$rules[] = array('60', 4, 4); // Directory Assistance (operator only) - Maybe shouldn't be in here
$rules[] = array('83', 5, 8); // "Enhanced Voice Services"
$rules[] = array('86', 8, 8); // "Enhanced Paging Services"
$rules[] = array('87', 4, 8); // "PSTN access to data services"
*/
// Mobile
$rules[] = array('20', 9, 9); // mobile radio / Orcon mobile
$rules[] = array('22', 8, 10); // NZ Communications (actual lengths subject to change)
$rules[] = array('210', 8, 10); // Vodafone
$rules[] = array('211', 8, 9); // Vodafone
$rules[] = array('212', 8, 9); // Vodafone
$rules[] = array('213', 8, 9); // Vodafone
$rules[] = array('214', 8, 9); // Vodafone
$rules[] = array('215', 8, 9); // Vodafone
$rules[] = array('216', 8, 9); // Vodafone
$rules[] = array('217', 8, 9); // Vodafone
$rules[] = array('218', 8, 9); // Vodafone
$rules[] = array('219', 8, 9); // Vodafone
$rules[] = array('24', 8, 8); // Scott Base
//$rules[] = array('25', 8, 9); // Old Telecom 025, now unused
$rules[] = array('26', 8, 9); // Telecom Paging
$rules[] = array('27', 9, 9); // Telecom 027 mobile
$rules[] = array('29', 8, 9); // TelstraClear mobile
// South Island regional
$rules[] = array('32', 8, 8);
$rules[] = array('33', 8, 8);
$rules[] = array('34', 8, 8);
$rules[] = array('35', 8, 8);
$rules[] = array('36', 8, 8);
$rules[] = array('37', 8, 8);
$rules[] = array('39', 8, 8);
// Wellington regional
$rules[] = array('42', 8, 8);
$rules[] = array('43', 8, 8);
$rules[] = array('44', 8, 8);
$rules[] = array('45', 8, 8);
$rules[] = array('46', 8, 8);
$rules[] = array('48', 8, 8);
$rules[] = array('49', 8, 8);
// Manawatu, Taranaki, Hawkes Bay, Gisborne, Wairarapa, Otaki regional
$rules[] = array('62', 8, 8);
$rules[] = array('63', 8, 8);
$rules[] = array('67', 8, 8);
$rules[] = array('68', 8, 8);
$rules[] = array('69', 8, 8);
// Waikato, BOP, Taumarunui regional
$rules[] = array('73', 8, 8);
$rules[] = array('75', 8, 8);
$rules[] = array('62', 8, 8);
$rules[] = array('78', 8, 8);
$rules[] = array('79', 8, 8);
// Freecall
$rules[] = array('80', 8, 10);
// Pay-call
$rules[] = array('90', 8, 10);
// Auckland + Northland regional
$rules[] = array('92', 8, 8);
$rules[] = array('93', 8, 8);
$rules[] = array('94', 8, 8);
$rules[] = array('95', 8, 8);
$rules[] = array('96', 8, 8);
$rules[] = array('98', 8, 8);
$rules[] = array('99', 8, 8);
foreach ($rules as $rule) {
if (preg_match('/^'.$rule[0].'/', $phonenumber) && strlen($phonenumber) >= $rule[1] && strlen($phonenumber) <= $rule[2]) {
return true;
}
}
return false;
}
/**
* Formatting for New Zealand Phone Numbers.
*
* @param string $phonenumber
* @return string Returns a string containing the phone number with some formatting.
*/
function format_nz_phone_number($phonenumber, $field) {
$prefix = '';
$extension = '';
// strip old formatting chars
$phonenumber = preg_replace('/[\-() ]/', '', $phonenumber);
/*
* strip and save the +64 prefix if found
*/
if (preg_match('/^\+64/', $phonenumber, $match)) {
$prefix = '+64';
$phonenumber = str_replace('+64', '', $phonenumber);
}
else {
$prefix = '0';
/*
* Remove a leading 0, if present
*/
if (preg_match('/^0/', $phonenumber, $match)) {
$phonenumber = substr($phonenumber, 1);
}
}
/*
* strip and save the extension (x9999) postfix if found
*/
if (preg_match('/(x[0-9]+)$/', $phonenumber, $match)) {
$extension = ' '.$match[1];
$phonenumber = preg_replace('/x[0-9]+$/', '', $phonenumber);
}
/*
* geographic numbers
* Eg. (04) 123 4578
*/
if (preg_match('/^([34679])([0-9]{3})([0-9]{4})$/', $phonenumber, $match)) {
return _format_nz_phone_number_prefix($prefix, $match[1]) . $match[2] . ' ' . $match[3] . $extension;
}
/*
* 8 digit mobile numbers
* Eg. 021 123 123
*/
if (preg_match('/^(2[12679])([0-9]{3})([0-9]{3})$/', $phonenumber, $match)) {
return _format_nz_phone_number_prefix($prefix, $match[1]) . $match[2] . ' ' . $match[3] . $extension;
}
/*
* 9 digit mobile numbers
* Eg. 021 123 4567
*/
if (preg_match('/^(2[12679])([0-9]{3})([0-9]{4})$/', $phonenumber, $match)) {
return _format_nz_phone_number_prefix($prefix, $match[1]) . $match[2] . ' ' . $match[3] . $extension;
}
/*
* 10 digit mobile numbers
* Eg. 021 1234 1234
*/
if (preg_match('/^(2[12679])([0-9]{4})([0-9]{4})$/', $phonenumber, $match)) {
return _format_nz_phone_number_prefix($prefix, $match[1]) . $match[2] . ' ' . $match[3] . $extension;
}
/**
* 0800/0900 numbers (a bit random)
*/
if (preg_match('/^(900|800)(\d+)$/', $phonenumber, $match)) {
// How we format depends on the length
$formatted = null;
switch(strlen($match[2])) {
case 5: $formatted = preg_replace('/^(\d{2})(\d{3})$/', '$1$2', $match[2]); break;
case 6: $formatted = preg_replace('/^(\d{3})(\d{3})$/', '$1$2', $match[2]); break;
case 7: $formatted = preg_replace('/^(\d{3})(\d{4})$/', '$1 $2', $match[2]); break;
}
return _format_nz_phone_number_prefix($prefix, $match[1]).$formatted;
}
// default (probably bad)
return $prefix . $phonenumber . $extension;
}
/**
* Formats the prefix as either +64 4 or (04), depending on the original prefix context
*
* @param string $prefix either '+64' or '0'
* @param string $area_code the area code, eg. 4, 21, 27 etc
* @return string the formatted prefix
*/
function _format_nz_phone_number_prefix($prefix, $area_code) {
$area_code = intval($area_code);
if (in_array($area_code, array('800', '900'))) {
return ($prefix == '0') ? $prefix.$area_code.' ' : $prefix.' '.$area_code.' ';
}
else {
return ($prefix == '0') ? '('.$prefix.$area_code.') ' : $prefix.' '.$area_code.' ';
}
}

View File

@@ -0,0 +1,70 @@
<?php
/**
* @file
* CCK field for Panamanian phone numbers
*/
/*
* ((00|\+)?[0-9]{3}[\s])? #First group 00507 or +507 (plus space)
* ([0-9]{3,4}) #Second group three or four numbers (four for cellphones)
* [\s|-]? space or dash
* ([0-9]{4}) #Third group
*
* Accepted:
* 00507 2603133
* +507 260-4343
* 260 3133
* 260-3133
*
* Cellphones
* +507 6545-4345
* 6545-4345
* 6545 4345
* 65454345
*/
define('PHONE_PA_REGEX', '/((00|\+)?[0-9]{3}[\s])?([0-9]{3,4})[\s|-]?([0-9]{4})/');
function phone_pa_metadata() {
// These strings are translated using t() on output.
return array(
'error' => '"%value" is not a valid Panamanian phone number!<br>Panamanian phone numbers should contain only numbers, spaces and dashes be like 9999-999, 9999 999 or 9999999 with an optional prefix of "+507" or "00507".',
);
}
/**
* Verifies that $phonenumber is a valid nine-digit Panamanian phone number
*
* @param string $phonenumber
* @return boolean Returns boolean FALSE if the phone number is not valid.
*/
function valid_pa_phone_number($phonenumber) {
//$phonenumber = trim($phonenumber);
// define regular expression
// return true if valid, false otherwise
return (bool) preg_match(PHONE_PA_REGEX, $phonenumber);
}
/**
* Convert a valid Panamenian phone number into standard (+507) 260-4324 format
*
* @param $phonenumber must be a valid nine-digit number (with optional international prefix)
*
*/
function format_pa_phone_number($phonenumber, $field = FALSE) {
// get digits of phone number
preg_match(PHONE_PA_REGEX, $phonenumber, $matches);
if (preg_match(PHONE_PA_REGEX, $phonenumber, $matches) != 1) {
return $phonenumber; // not a Panamanian phone number
}
$phonenumber = $matches[3] . '-' . $matches[4];
if (trim($matches[1]) != '') {
$phonenumber = '+' . substr($matches[1], -4) . $phonenumber;
}
elseif ($field && isset($field['phone_country_code'])) {
$phonenumber = '+507 ' . $phonenumber;
}
return $phonenumber;
}

View File

@@ -0,0 +1,127 @@
<?php
/**
* @file
* CCK Field for Philippine phone numbers.
*/
function phone_ph_metadata() {
// These strings are translated using t() on output.
return array(
'error' => '"%value" is not a valid Philippine phone number<br />Example of valid Philippine phone numbers: +63 (2) 123-4567 or +63 (2) 123-4567 loc. 123 or mobile +63 (919) 123-4567',
);
}
/**
* Verifies that $phonenumber is a valid ten-digit Philippine phone number
*
* @param string $phonenumber
* @return boolean Returns boolean FALSE if the phone number is not valid.
*/
function valid_ph_phone_number($phonenumber) {
/*
Accepts:
+63197071234567
+63197071234567
+63(19707) 1234567
+63(19707) 123-4567
+63 19707 123 4567
+63 19707 123-4567
(19707) 1234567 loc. 1234
*/
$regex = "/
(
(^\+63\s?\(?\d{5}\)?|^\(?\d{5}\)?){1}\s?\d{3}(\S?|\s?)?\d{4} # 5 digit area code with optional +63 internationalisation or not, optional spaces and brackets.
|
(^\+63\s?\(?\d{4}\)?|^\(?\d{4}\)?){1}\s?\d{3}(\S?|\s?)?\d{4} # 4 digit area code with optional +63 internationalisation or not, optional spaces and brackets.
|
(^\+63\s?\(?\d{3}\)?|^\(?\d{3}\)?){1}\s?\d{3}(\S?|\s?)?\d{4} # 3 digit area code with optional +63 internationalisation or not, optional spaces and brackets.
|
(^\+63\s?\(?\d{2}\)?|^\(?\d{2}\)?){1}\s?\d{3}(\S?|\s?)?\d{4} # 2 digit area code with optional +63 internationalisation or not, optional spaces and brackets.
|
(^\+63\s?\(?\d{1}\)?|^\(?\d{1}\)?){1}\s?\d{3}(\S?|\s?)?\d{4} # 1 digit area code with optional +63 internationalisation or not, optional spaces and brackets.
)
(\s?\#\d*)? # optional extension number shown with a loc. divider
/x";
// return true if valid, false otherwise
if (!preg_match($regex, $phonenumber)) {
return FALSE;
}
else
{
return TRUE;
}
}
/**
* Convert a valid Philippine phone number into standard +63 (2) 123-4567 or +63 (2) 123-4567 loc. 123 or mobile +63 (919) 123-4567
*
* @param $phonenumber must be a valid ten-digit number (with optional extension)
*
*/
function format_ph_phone_number($phonenumber, $field = FALSE) {
$area = $number = $extension = $description = '';
//Simplify to 10 digit number and clean up ready for international reformat.
$phonenumber = preg_replace("/^\+63/","",$phonenumber);
$phonenumber = preg_replace("/\(/","",$phonenumber);
$phonenumber = preg_replace("/\)/","",$phonenumber);
//If there are some spaces in the number assume some level of preformatting
$regex = "/
# 5 digit area code.
(
(\d{5}) # capture 5 digit area code
(\s*)? # ignore required separator to make a distinction with other area codes
(\d{3}) # capture first set of numbers in the local number
(\S?|\s*)? # ignore optional separator
(\d{4}) # capture second set of numbers in the local number
|
# 4 digit area code.
(\d{4}) # capture 4 digit area code
(\s*)? # ignore required seperator
(\d{3}) # capture first set of numbers in the local number
(\S?|\s*)? # ignore possible boundary
(\d{4}) # capture second set of numbers in the local number
|
# 3 digit area code.
(\d{3}) # capture 3 digit area code
(\s*)? # ignore required seperator
(\d{3}) # capture first set of numbers in the local number
(\S?|\s*)? # ignore possible boundary
(\d{4}) # capture second set of numbers in the local number
|
# 2 digit area code.
(\d{2}) # capture 2 digit area code
(\s*)? # ignore required seperator
(\d{3}) # capture first set of numbers in the local number
(\S?|\s*)? # ignore possible boundary
(\d{4}) # capture second set of numbers in the local number
|
# 1 digit area code.
(\d{1}) # capture 1 digit area code
(\s*)? # ignore required boundary to make a distinction with other area codes
(\d{3}) # capture first set of numbers in the local number
(\S?|\s*)? # ignore possible boundary
(\d{4}) # capture second set of numbers in the local number
)
# capture the optional extension number
(\s*loc\.\s*|\s*ext\.\s*)?
(\d*)?
([a-zA-Z0-9\-\. \/\,\']{0,})?
/x";
preg_match($regex, $phonenumber, $matches);
$area = $matches[2] . $matches[7] . $matches[12] . $matches[17] . $matches[22];
$number = $matches[4] . $matches[9] . $matches[14] . $matches[19] . $matches[24] . '-' . $matches[6] . $matches[11] . $matches[16] . $matches[21] . $matches[26];
$extension = $matches[28];
$description = $matches[29];
$phonenumber = '+63 (' . $area . ') ' . $number;
$phonenumber .= (empty($extension)) ? '' : " loc. $extension";
$phonenumber .= (empty($description))? '' : " $description";
return $phonenumber;
}

View File

@@ -0,0 +1,49 @@
<?php
/**
* @file
* CCK Field for Pakistanese phone numbers.
*/
function phone_pk_metadata() {
// These strings are translated using t() on output.
return array(
'error' => '"%value" is not a valid Pakistanese mobile phone number<br>Pakistanese phone numbers should only ...',
);
}
/**
* Verifies that $phonenumber is valid
*
* @param string $phonenumber
* @return boolean Returns boolean FALSE if the phone number is not valid.
*/
function valid_pk_phone_number($phonenumber) {
// define regular expression
$regex = "/^(\+)?([9]{1}[2]{1})?-? ?(\()?([0]{1})?[1-9]{2,4}(\))?-? ??(\()?[1-9]{4,7}(\))?$/i";
// return true if valid, false otherwise
return (bool) preg_match($regex, $phonenumber);
}
/**
* Formatting for Pakistan Phone Numbers.
*
* @param string $phonenumber
* @return string Returns a string containting the phone number with some formatting.
*/
function format_pk_phone_number($phonenumber, $field) {
//$phonenumber = trim($phonenumber);
// do some formatting on the phone number
/* ==> to be done ==> add the country code
if ($field['phone_country_code']) {
if ($matches[1] != "+39") {
$phonenumber = "+39" . " " . $phonenumber;
}
}
*/
return $phonenumber;
}

View File

@@ -0,0 +1,49 @@
<?php
/**
* @file
* CCK Field for Poland phone numbers.
*/
function phone_pl_metadata() {
// These strings are translated using t() on output.
return array(
'error' => '"%value" is not a valid Polish mobile phone number<br>Polish phone numbers should only ...',
);
}
/**
* Verifies that $phonenumber is valid
*
* @param string $phonenumber
* @return boolean Returns boolean FALSE if the phone number is not valid.
*/
function valid_pl_phone_number($phonenumber) {
// define regular expression
$regex = "/^(\+48\s+)?\d{3}(\s*|\-)\d{3}(\s*|\-)\d{3}$/i";
// return true if valid, false otherwise
return (bool) preg_match($regex, $phonenumber);
}
/**
* Formatting for Polish Phone Numbers.
*
* @param string $phonenumber
* @return string Returns a string containting the phone number with some formatting.
*/
function format_pl_phone_number($phonenumber, $field) {
//$phonenumber = trim($phonenumber);
// do some formatting on the phone number
/* ==> to be done ==> add the country code
if ($field['phone_country_code']) {
if ($matches[1] != "+39") {
$phonenumber = "+39" . " " . $phonenumber;
}
}
*/
return $phonenumber;
}

View File

@@ -0,0 +1,74 @@
<?php
/**
* @file
* CCK Field for Russian phone numbers.
*/
function phone_ru_metadata() {
// These strings are translated using t() on output.
return array(
'error' => '"%value" is not a valid Russian phone number<br>Russian Phone numbers should .... ',
);
}
/**
* Verifies that $phonenumber is a valid ten-digit Russian phone number
*
* @param string $phonenumber
* @return boolean Returns boolean FALSE if the phone number is not valid.
*/
function valid_ru_phone_number($phonenumber) {
//$phonenumber = trim($phonenumber);
// define regular expression
$regex = "/
\D* # ignore non-digits
[78]? # an optional 78
\D* # optional separator
\d{3,5} # area code 3-5 digit
\D* # optional separator
\d{1,3} # 3-digit prefix
\D* # optional separator
\d{2} # 2-digit line number
\D* # optional separator
\d{2} # 2-digit line number
\D* # ignore trailing non-digits
/x";
// return true if valid, false otherwise
return (bool) preg_match($regex, $phonenumber);
}
/**
* Convert a valid Russian phone number into standard +7 (495) 567-53-09 or +7 (444xx) 67-53-09 or mobile 8 910 414-56-90 format
*
* @param $phonenumber must be a valid ten-digit number (with optional extension)
*
*/
function format_ru_phone_number($phonenumber, $field = FALSE) {
// define regular expression
$regex = "/
^\D* # ignore non-digits
([78])? # an optional 78
\D* # optional separator
(\d{3,5}) # area code 3-5 digit
\D* # optional separator
(\d{1,3}) # capture 3-digit prefix
\D* # optional separator
(\d{2}) # 2-digit line number
\D* # optional separator
(\d{2}) # 2-digit line number
\D* # ignore trailing non-digits
/x";
// get digits of phone number
preg_match($regex, $phonenumber, $matches);
// construct ten-digit phone number
$phonenumber = $matches[1] . ' (' . $matches[2] . ') ' . $matches[3] . ' - ' . $matches[4] . ' - ' . $matches[5];
return $phonenumber;
}

View File

@@ -0,0 +1,49 @@
<?php
/**
* @file
* CCK Field for Swedish phone numbers.
*/
function phone_se_metadata() {
// These strings are translated using t() on output.
return array(
'error' => '"%value" is not a valid Swedish mobile phone number<br>Swedish phone numbers should only ...',
);
}
/**
* Verifies that $phonenumber is valid
*
* @param string $phonenumber
* @return boolean Returns boolean FALSE if the phone number is not valid.
*/
function valid_se_phone_number($phonenumber) {
// define regular expression
$regex = "/^(([+]\d{2}[ ][1-9]\d{0,2}[ ])|([0]\d{1,3}[-]))((\d{2}([ ]\d{2}){2})|(\d{3}([ ]\d{3})*([ ]\d{2})+))$/i";
// return true if valid, false otherwise
return (bool) preg_match($regex, $phonenumber);
}
/**
* Formatting for Sweden Phone Numbers.
*
* @param string $phonenumber
* @return string Returns a string containting the phone number with some formatting.
*/
function format_se_phone_number($phonenumber, $field) {
//$phonenumber = trim($phonenumber);
// do some formatting on the phone number
/* ==> to be done ==> add the country code
if ($field['phone_country_code']) {
if ($matches[1] != "+39") {
$phonenumber = "+39" . " " . $phonenumber;
}
}
*/
return $phonenumber;
}

View File

@@ -0,0 +1,59 @@
<?php
/**
* @file
* CCK Field for Singapore phone numbers.
*/
function phone_sg_metadata() {
// These strings are translated using t() on output.
return array(
'error' => '"%value" is not a valid Singaporean phone number<br>Singaporean phone numbers should only ...',
);
}
/**
* Verifies that $phonenumber is valid
*
* @param string $phonenumber
* @return boolean Returns boolean FALSE if the phone number is not valid.
*/
function valid_sg_phone_number($phonenumber) {
// define regular expression
/*
See: http://en.wikipedia.org/wiki/Telephone_numbers_in_Singapore
Accepts:
+6561234567 / +6581234567 / +6591234567
+65 61234567 / +65 81234567 / +65 91234567
61234567 / 81234567 / 91234567
*/
$regex = '/^(\+65)?\s?[689]\d{7}$/i';
// return true if valid, false otherwise
return (bool) preg_match($regex, $phonenumber);
}
/**
* Formatting for Singapore Phone Numbers.
*
* @param string $phonenumber
* @return string Returns a string containting the phone number with some formatting.
*/
function format_sg_phone_number($phonenumber, $field) {
//$phonenumber = trim($phonenumber);
// do some formatting on the phone number
/* ==> to be done ==> add the country code
if ($field['phone_country_code']) {
if ($matches[1] != "+39") {
$phonenumber = "+39" . " " . $phonenumber;
}
}
*/
return $phonenumber;
}

View File

@@ -0,0 +1,49 @@
<?php
/**
* @file
* CCK Field for Senegalese phone numbers.
*/
define('PHONE_SN_REGEX', '/((\+221|00221)?)((7[7608][0-9]{7}$)|(3[03][98][0-9]{6}$))/');
function phone_sn_metadata() {
// These strings are translated using t() on output.
return array(
'error' => '"%value" is not a valid Senegalese phone number',
);
}
/**
* Verification for Senegalese Phone Numbers.
*
* @param string $phonenumber
* @return boolean Returns boolean FALSE if the phone number is not valid.
*/
function valid_sn_phone_number($phonenumber) {
$phonenumber = str_replace(array(' ', '-', '(', ')') , '', $phonenumber);
return (bool) preg_match(PHONE_SN_REGEX, $phonenumber);
}
/**
* Formatting for Senegalese Phone Numbers.
*
* @param string $phonenumber
* @return string Returns the phone number as string.
*/
function format_sn_phone_number($phonenumber, $field = FALSE) {
$phone = str_replace(array(' ', '-', '(', ')'), '', $phonenumber);
if (preg_match(PHONE_SN_REGEX, $phone, $matches) != 1) {
return $phonenumber; // not a french phone number
}
//
if (in_array($matches[0], array('+221', '00221'))) {
return $matches[2];
}
else {
return $matches[0];
}
}

View File

@@ -0,0 +1,581 @@
<?php
/**
* @file
* CCK Field for Ukrainian phone numbers.
*/
/**
* Helper function knows all valid country codes.
*
* @return array of stings for use in preg_match* fuunctions.
*
* Return PREG string elements in array like "44\d{7}|278\d{6}" which will match
* all nine-digit valid numbers.
* Please note - leading zero stripped for both mobile and landline.
*
* For performance reason there are a set of strings instead of single very long one.
*/
function _phone_ua_get_valid_masks() {
$result = cache_get('phone' . __FUNCTION__);
if( !empty($result) ) {
return $result->data;
}
$mobiles = array(
"39",
"50",
"63",
"66",
"67",
"68",
"91",
"92",
"93",
"94",
"95",
"96",
"97",
"98",
"99",
);
$landlines = array(
"255",
"260",
"263",
"265",
"268",
"269",
"271",
"272",
"278",
"312",
"3131",
"3132",
"3133",
"3134",
"3135",
"3136",
"3137",
"3141",
"3142",
"3143",
"3144",
"3145",
"3146",
"322",
"3230",
"3231",
"3234",
"3236",
"3238",
"3239",
"3241",
"3244",
"3245",
"3247",
"3248",
"3249",
"3251",
"3252",
"3254",
"3255",
"3256",
"3257",
"3259",
"32606",
"3261",
"3263",
"3264",
"3265",
"3266",
"3269",
"3310",
"3322",
"3342",
"3344",
"3346",
"3348",
"3352",
"3355",
"3357",
"3362",
"3363",
"3365",
"3366",
"3368",
"3372",
"3374",
"3376",
"3377",
"3379",
"342",
"3430",
"3431",
"3432",
"3433",
"3434",
"3435",
"3436",
"3438",
"3471",
"3472",
"3474",
"3475",
"3476",
"3477",
"3478",
"3479",
"352",
"3540",
"3541",
"3542",
"3543",
"3544",
"3546",
"3547",
"3548",
"3549",
"3550",
"3551",
"3552",
"3554",
"3555",
"3557",
"3558",
"362",
"3632",
"3633",
"3634",
"3635",
"3636",
"3637",
"3650",
"3651",
"3652",
"3653",
"3654",
"3655",
"3656",
"3657",
"3658",
"3659",
"372",
"373",
"3740",
"3741",
"382",
"384",
"385",
"412",
"4130",
"4132",
"4133",
"4134",
"4135",
"4136",
"4137",
"4138",
"4139",
"414",
"4161",
"4162",
"4231",
"4232",
"4241",
"432",
"4330",
"4331",
"4332",
"4333",
"4334",
"4335",
"4336",
"4337",
"43388",
"4340",
"4341",
"4342",
"4343",
"4344",
"4345",
"4346",
"4347",
"4348",
"4349",
"4350",
"4351",
"4352",
"4353",
"4355",
"4356",
"4357",
"4358",
"44",
"462",
"4631",
"4632",
"4633",
"4634",
"4635",
"4636",
"4637",
"4641",
"4642",
"4643",
"4644",
"4645",
"4646",
"4653",
"4654",
"4655",
"4656",
"4657",
"4658",
"4659",
"472",
"473",
"4740",
"4741",
"4742",
"4744",
"4745",
"4746",
"4747",
"4748",
"4749",
"482",
"484",
"4851",
"4852",
"4853",
"4854",
"4855",
"4856",
"4857",
"4858",
"4859",
"4860",
"4861",
"4862",
"4863",
"4864",
"4865",
"4866",
"4867",
"4868",
"512",
"5131",
"5132",
"5133",
"5134",
"5135",
"5136",
"5151",
"5152",
"5153",
"5154",
"5158",
"5159",
"5161",
"5162",
"5163",
"5167",
"5168",
"522",
"5233",
"5234",
"5235",
"5236",
"5237",
"5238",
"5239",
"5240",
"5241",
"5242",
"5250",
"5251",
"5252",
"5253",
"5254",
"5256",
"5257",
"5258",
"5259",
"532",
"5340",
"5341",
"5342",
"5343",
"5344",
"5345",
"5346",
"5347",
"5348",
"5350",
"5351",
"5352",
"5353",
"5354",
"5355",
"5356",
"5357",
"5358",
"5359",
"536",
"5361",
"5362",
"5363",
"5364",
"5365",
"5366",
"542",
"5422",
"5442",
"5443",
"5444",
"5445",
"5446",
"5447",
"5448",
"5449",
"5451",
"5452",
"5453",
"5454",
"5455",
"5456",
"5457",
"5458",
"5459",
"552",
"553",
"5542",
"5543",
"5544",
"5545",
"5546",
"5547",
"5548",
"5549",
"56",
"5610",
"5611",
"5612",
"5615",
"5616",
"5617",
"5618",
"562",
"5630",
"5632",
"5633",
"5636",
"5638",
"5639",
"564",
"5650",
"5651",
"5652",
"5653",
"5655",
"5656",
"5657",
"5658",
"5662",
"5663",
"5665",
"5667",
"5668",
"567",
"569",
"572",
"574",
"575",
"5761",
"5762",
"5763",
"5764",
"5765",
"5766",
"612",
"6131",
"6132",
"6133",
"6136",
"6137",
"6138",
"6139",
"6140",
"6141",
"6142",
"6143",
"6144",
"6145",
"6147",
"6153",
"6156",
"6162",
"6165",
"6175",
"6178",
"619",
"6212",
"6214",
"6217",
"622",
"6232",
"6236",
"6237",
"6239",
"6242",
"6243",
"6244",
"6246",
"6247",
"6249",
"6250",
"6252",
"6253",
"6254",
"6255",
"6256",
"6257",
"6259",
"6261",
"6262",
"6264",
"6267",
"6269",
"6272",
"6273",
"6274",
"6275",
"6277",
"6278",
"6279",
"629",
"642",
"6431",
"6432",
"6433",
"6434",
"6435",
"6436",
"6441",
"6442",
"6443",
"6444",
"6445",
"6446",
"6451",
"6452",
"6453",
"6454",
"6455",
"6456",
"6461",
"6462",
"6463",
"6464",
"6465",
"6466",
"6471",
"6472",
"6473",
"6474",
"652",
"654",
"655",
"6560",
"6561",
"6562",
"6563",
"6564",
"6565",
"6566",
"6569",
"692",
);
$all_codes = array_merge($mobiles, $landlines);
$TOTAL_DIGITS = 9;
$ITEMS_PER_LINE = 30;
$counter = 0;
$line = '';
foreach ($all_codes as $code) {
if (++$counter >= $ITEMS_PER_LINE) {
$result[] = $line;
$counter = 0;
$line = '';
}
$item = $code . '\d{' . ($TOTAL_DIGITS - strlen($code)) . '}';
$line .= (empty($line) ? '' : '|') . $item;
}
$result[] = $line;
cache_set('phone' . __FUNCTION__, $result);
return $result;
}
function phone_ua_metadata() {
// These strings are translated using t() on output.
return array(
'error' => '"%value" is not a valid Ukrainian mobile phone number<br />'
. 'Ukrainian phone numbers should only have 10 digits staring with 0 with optional country prefix +38 .<br />'
. 'And, of course, city or mobile code - a first few digits after 0 - have to be valid.',
);
}
/**
* Verifies that $phonenumber is valid
*
* @param string $phonenumber
* @return boolean Returns boolean FALSE if the phone number is not valid.
*/
function valid_ua_phone_number($phonenumber) {
// For adressing Ukraine phones used both +38 and +380 as a prefix.
// So lets clean up any spaces, pareenthesis, minus signs etc first.
$cleaning_pattern = '/( |\-|\(|\))*/';
$refined_phonenumber = preg_replace($cleaning_pattern, '', $phonenumber);
// define regular expression
$code_packs = _phone_ua_get_valid_masks();
foreach ($code_packs as $codes) {
// $regex = "/^((8|\+38)-?)?\s*(\(?044\)?)?-?\d{3}-?\d{2}-?\d{2}$/i";
// Please note - pure 8 as a prefix is obsolete.
$regex = "/^(\+38)?0(" . $codes . ")$/";
if (preg_match($regex, $refined_phonenumber)) {
return true;
}
}
// return true if valid, false otherwise
return false;
}
/**
* Formatting for Unkraine Phone Numbers.
*
* @param string $phonenumber
* @return string Returns a string containting the phone number with some formatting.
*/
function format_ua_phone_number($phonenumber, $field) {
//$phonenumber = trim($phonenumber);
// do some formatting on the phone number
/* ==> to be done ==> add the country code
if ($field['phone_country_code']) {
if ($matches[1] != "+39") {
$phonenumber = "+39" . " " . $phonenumber;
}
}
*/
return $phonenumber;
}

View File

@@ -0,0 +1,65 @@
<?php
/**
* @file
* CCK Field for South African phone numbers.
*/
function phone_za_metadata() {
// These strings are translated using t() on output.
return array(
'error' => '"%value" is not a valid South African phone number!<br>South African phone numbers should only contain numbers with an optional prefix of "+27".',
);
}
/**
* Verifies that $phonenumber is a valid South African phone number
*
* @param string $phonenumber
* @return boolean Returns boolean FALSE if the phone number is not valid.
*/
function valid_za_phone_number($phonenumber) {
$phonenumber = trim($phonenumber);
// define regular expression
$regex = '/^((?:\+27|27)|0)[ ]*((\d{2})(-| )?(\d{3})(-| )?(\d{4})|(\d{2})( |-)(\d{7}))$/';
// return true if valid, false otherwise
return (bool) preg_match($regex, $phonenumber);
}
/**
* Convert a valid South African phone number into standard ... format
*
* @param $phonenumber must be a valid ... digit number (with optional international prefix)
*
*/
function format_za_phone_number($phonenumber, $field) {
// define regular expression
$regex = '/^((?:\+27|27)|0)[ ]*((\d{2})(-| )?(\d{3})(-| )?(\d{4})|(\d{2})( |-)(\d{7}))$/';
// get digits of phone number
preg_match($regex, $phonenumber, $matches);
/*
drupal_set_message('$matches[1] = ' . $matches[1], 'error');
drupal_set_message('$matches[2] = ' . $matches[2], 'error');
drupal_set_message('$matches[3] = ' . $matches[3], 'error');
drupal_set_message('$matches[4] = ' . $matches[4], 'error');
drupal_set_message('$matches[5] = ' . $matches[5], 'error');
drupal_set_message('$matches[6] = ' . $matches[6], 'error');
drupal_set_message('$matches[7] = ' . $matches[7], 'error');
drupal_set_message('$matches[8] = ' . $matches[8], 'error');
*/
if ($field['phone_country_code']) {
$phonenumber = '+27' . ' ' . $matches[3] .'-'. $matches[5] .'-'. $matches[7];
}
else {
$phonenumber = '0' . $matches[3] .'-'. $matches[5] .'-'. $matches[7];
}
return $phonenumber;
}

View File

@@ -0,0 +1,59 @@
<?php
/**
* @file
* Implements Feeds support for Phone fields.
*/
/**
* Implements hook_feeds_processor_targets_alter().
*
* @see FeedsNodeProcessor::getMappingTargets().
*/
function phone_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_name) {
foreach (field_info_instances($entity_type, $bundle_name) as $name => $instance) {
$info = field_info_field($name);
if ($info['type'] == 'phone') {
$targets[$name . ':url'] = array(
'name' => check_plain($instance['label']),
'callback' => 'phone_feeds_set_target',
'description' => t('The @label field of the node.', array('@label' => $instance['label'])),
);
}
}
}
/**
* Callback for mapping. Here is where the actual mapping happens.
*
* When the callback is invoked, $target contains the name of the field the
* user has decided to map to and $value contains the value of the feed item
* element the user has picked as a source.
*/
function phone_feeds_set_target($source, $entity, $target, $value) {
if (empty($value)) {
return;
}
// Handle non-multiple value fields.
if (!is_array($value)) {
$value = array($value);
}
// Iterate over all values.
$i = 0;
$info = field_info_field($target);
list($field_name, $sub_field) = explode(':', $target);
foreach ($value as $v) {
if (empty($v[0])) {
continue;
}
if (!is_array($v) && !is_object($v)) {
$field['und'][$i]['value'] = $v;
}
if ($info['cardinality'] == 1) {
break;
}
$i++;
}
$entity->{$field_name} = $field;
}

View File

@@ -0,0 +1,42 @@
name = Phone
description = The phone module allows administrators to define a field type for phone numbers.
package = Fields
dependencies[] = field
files[] = phone.migrate.inc
files[] = tests/phone.au.test
files[] = tests/phone.be.test
files[] = tests/phone.br.test
files[] = tests/phone.ca.test
files[] = tests/phone.ch.test
files[] = tests/phone.cl.test
files[] = tests/phone.cn.test
files[] = tests/phone.cr.test
files[] = tests/phone.cs.test
files[] = tests/phone.eg.test
files[] = tests/phone.es.test
files[] = tests/phone.fr.test
files[] = tests/phone.hu.test
files[] = tests/phone.il.test
files[] = tests/phone.int.test
files[] = tests/phone.it.test
files[] = tests/phone.jo.test
files[] = tests/phone.nl.test
files[] = tests/phone.nz.test
files[] = tests/phone.pa.test
files[] = tests/phone.ph.test
files[] = tests/phone.pk.test
files[] = tests/phone.pl.test
files[] = tests/phone.ru.test
files[] = tests/phone.se.test
files[] = tests/phone.sg.test
files[] = tests/phone.ua.test
files[] = tests/phone.uk.test
files[] = tests/phone.za.test
core = 7.x
; Information added by Drupal.org packaging script on 2014-01-14
version = "7.x-1.0-beta1"
core = "7.x"
project = "phone"
datestamp = "1389732224"

View File

@@ -0,0 +1,25 @@
<?php
/**
* @file
* Install/Update/Uninstall functions for phone module
*/
/**
* Implements hook_field_schema().
*/
function phone_field_schema($field) {
return array(
'columns' => array(
'value' => array(
'type' => 'varchar',
'length' => 255,
'not null' => FALSE,
),
),
);
}
// TODO: data migration from the old DB structure, could be tough..

View File

@@ -0,0 +1,40 @@
<?php
/**
* @file phone.migrate.inc
* Code to implement hook_content_migrate_field_alter, content_migrate_instance_alter() and content_migrate_data_record_alter()
* on behalf of the former phone module, moved into a separate file for efficiency.
*/
/**
* Implements hook_content_migrate_field_alter().
*
* Use this to tweak the conversion of field settings
* from the D6 style to the D7 style for specific
* situations not handled by basic conversion,
* as when field types or settings are changed.
*/
function phone_field_alter(&$field_value, $instance_value) {
if (substr($field_value['type'], 2) === '_phone') {
$code = substr($field_value['type'], 0, 2);
$field_value['type'] = 'phone';
$field_value['settings']['country'] = $code;
}
}
/**
* Implements hook_migrate_api().
*/
function phone_migrate_api() {
return array('api' => 2);
}
/**
* Wrap Migrate's simple field handler for 'phone' fields.
*/
class MigratePhoneFieldHandler extends MigrateSimpleFieldHandler {
public function __construct() {
$this->registerTypes(array('phone'));
}
}

View File

@@ -0,0 +1,386 @@
<?php
/**
* Function which holds an array of supported countries.
*
* @param string $countrycode
* @return boolean Returns the whole array of countries $countrycode isn't specified and a country name for when it is specified.
*/
function phone_countries($code = NULL) {
static $countries;
if (!isset($countries)) {
$countries = array(
'fr' => 'France',
'be' => 'Belgium',
'it' => 'Italy',
'el' => 'Greece',
'ch' => 'Switzerland',
'ca' => 'US & Canada',
'cr' => 'Costa Rica',
'pa' => 'Panama',
'gb' => 'Great Britain - United Kingdom',
'ru' => 'Russia',
'ua' => 'Ukraine',
'es' => 'Spain',
'au' => 'Australia',
'cs' => 'Czech Republic',
'hu' => 'Hungary',
'pl' => 'Poland - mobiles only',
'nl' => 'Netherland',
'se' => 'Sweden',
'za' => 'South Africa',
'il' => 'Israel',
'nz' => 'New Zealand',
'br' => 'Brazil',
'cl' => 'Chile',
'cn' => 'China',
'hk' => 'Hong-Kong',
'mo' => 'Macao',
'ph' => 'The Philippines',
'sg' => 'Singapore',
'sn' => 'Senegal',
'jo' => 'Jordan',
'eg' => 'Egypt',
'pk' => 'Pakistan',
'int' => 'International Phone Numbers per E.123',
);
}
return ($code === NULL) ? $countries : (isset($countries[$code]) ? $countries[$code] : NULL);
}
/**
* @defgroup field_api_hooks Field API Hook Implementations
*/
/**
* Implementation of hook_field_info().
*/
function phone_field_info() {
return array(
'phone' => array(
'label' => t('Phone Number'),
'instance_settings' => array(
'phone_country_code' => 0,
'phone_default_country_code' => '1',
'phone_int_max_length' => 15,
'ca_phone_separator' => '-',
'ca_phone_parentheses' => 1,
),
'default_formatter' => 'phone',
'default_widget' => 'phone_textfield',
'property_type' => 'text',
),
);
}
/**
* Implements hook_field_is_empty().
*/
function phone_field_is_empty($item, $field) {
return empty($item['value']);
}
/**
* Implements hook_field_settings_form().
*/
function phone_field_settings_form($field, $instance, $has_data) {
$settings = $field['settings'];
$form = array();
$form['country'] = array(
'#type' => 'select',
'#title' => t('Country'),
'#options' => phone_countries(),
'#default_value' => isset ($settings['country']) ? $settings['country'] : NULL,
'#description' => t('Which country-specific rules should this field be validated against and formatted according to.'),
'#disabled' => $has_data,
'#required' => TRUE,
);
return $form;
}
/**
* Implements hook_field_instance_settings_form().
*/
function phone_field_instance_settings_form($field, $instance) {
$settings = $instance['settings'];
$form['phone_country_code'] = array(
'#type' => 'checkbox',
'#title' => t('Add the country code if not filled by the user'),
'#default_value' => $settings['phone_country_code'],
);
if ($field['settings']['country'] == 'int') {
$form['phone_int_help'] = array(
'#type' => 'markup',
'#value' => t('International phone numbers are in the form +XX YYYYYYY where XX is a country code and YYYYYYY is the local number. This field type is based off of the <a href="http://www.itu.int/rec/T-REC-E.123/en">E.123 specification</a>.'),
);
$form['phone_default_country_code'] = array(
'#type' => 'textfield',
'#title' => t('Default country code to add to international numbers without one (omit + sign)'),
'#default_value' => $settings['phone_default_country_code'],
);
$form['phone_int_max_length'] = array(
'#type' => 'textfield',
'#title' => t('Maximum length of international numbers, according to the ITU this is 15'),
'#default_value' => $settings['phone_int_max_length'],
);
}
if ($field['settings']['country'] == 'ca') {
$form['ca_phone_separator'] = array(
'#type' => 'textfield',
'#title' => t('Separator'),
'#default_value' => $settings['ca_phone_separator'],
'#size' => 2,
);
$form['ca_phone_parentheses'] = array(
'#type' => 'checkbox',
'#title' => t('Use parentheses around area code'),
'#default_value' => $settings['ca_phone_parentheses'],
);
}
return $form;
}
/**
* Implements hook_field_validate().
*/
function phone_field_validate($entity_type, $entity, $field, $instance, $langcode, $items, &$errors) {
foreach ($items as $delta => $item) {
if (isset($item['value']) && $item['value'] != '') {
$ccode = $field['settings']['country'];
$value = $item['value'];
if (!valid_phone_number($ccode, $value)) {
$country = phone_country_info($ccode);
$errors[$field['field_name']][$langcode][$delta][] = array(
'error' => 'phone_invalid_number',
'message' => t($country['error'], array('%value' => $value)),
);
}
}
}
}
/**
* Implements hook_field_presave().
*/
function phone_field_presave($entity_type, $entity, $field, $instance, $langcode, &$items) {
$ccode = $field['settings']['country'];
if (phone_countries($ccode) !== NULL) {
foreach ($items as $delta => $item) {
if (isset($item['value'])) {
$items[$delta]['value'] = format_phone_number($ccode, $item['value'], $instance['settings']);
}
}
}
}
/**
* Implements hook_field_formatter_info().
*/
function phone_field_formatter_info() {
return array(
'phone' => array(
'label' => t('Default'),
'field types' => array('phone'),
)
);
}
/**
* Implements hook_field_formatter_view().
*/
function phone_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
$element = array();
foreach ($items as $delta => $item) {
$text = '';
if (isset($item['value'])) {
$text = check_plain($item['value']);
// iPhone Support
if (strpos($_SERVER['HTTP_USER_AGENT'], 'iPhone') !== FALSE) {
$text = '<a href="tel:' . $text . '">' . $text . '</a>';
}
}
$element[$delta]['#markup'] = $text;
}
return $element;
}
/**
* Implements hook_field_widget_info().
*/
function phone_field_widget_info() {
return array(
'phone_textfield' => array(
'label' => t('Text field'),
'field types' => array('phone'),
),
);
}
/**
* Implements hook_field_widget_form().
*/
function phone_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
$element += array(
'#type' => 'textfield',
'#title' => $element['#title'],
'#description' => $element['#description'],
'#default_value' => isset($items[$delta]['value']) ? $items[$delta]['value'] : '',
'#required' => $element['#required'],
'#size' => 17,
'#maxlength' => (
$field['settings']['country'] == 'int' ?
(isset($instance['settings']['phone_int_max_length']) ? $instance['settings']['phone_int_max_length'] : NULL)
: NULL
),
);
return array('value' => $element);
}
/**
* @} End of "defgroup field_api_hooks".
*/
/**
* @defgroup other_hooks Other Hook Implementations
*/
/**
* Implements hook_content_migrate_field_alter().
*
* Use this to tweak the conversion of field settings
* from the D6 style to the D7 style for specific
* situations not handled by basic conversion,
* as when field types or settings are changed.
*/
function phone_content_migrate_field_alter(&$field_value, $instance_value) {
module_load_include('inc', 'phone', 'phone.migrate');
phone_field_alter($field_value, $instance_value);
}
/**
* Implementation of hook token_list
*/
function phone_token_list($type = 'all') {
if ($type == 'field' || $type == 'all') {
$tokens['phone']['raw'] = t('Raw phone numbers');
$tokens['phone']['formatted'] = t('Formatted phone numbers');
return $tokens;
}
}
/**
* Implementation of hook token_values
*/
function phone_token_values($type, $object = NULL, $options = array()) {
if ($type == 'field') {
$item = $object[0];
$tokens['raw'] = $item['value'];
$tokens['formatted'] = $item['view'];
return $tokens;
}
}
/**
* Implementation of hook_simpletest().
*/
function phone_simpletest() {
$dir = drupal_get_path('module', 'phone'). '/tests';
$tests = file_scan_directory($dir, '\.test$');
return array_keys($tests);
}
/**
* @} End of "defgroup field_api_hooks".
*/
/**
* Country supported or not by the module ?
*
* @param string $countrycode
* @return boolean Returns a boolean containting the answer to the question.
*/
function phone_supported_countrycode($countrycode) {
return (phone_country_info($countrycode) !== NULL ? TRUE : FALSE);
}
/**
* Get a country meta info
*
* @param string $countrycode
* @return array Returns a array containing country metadata
*/
function phone_country_info($countrycode = NULL) {
static $i;
$countrycode = trim($countrycode);
if (phone_countries($countrycode) !== FALSE) {
$phone_info_function = 'phone_'. $countrycode . '_metadata';
module_load_include('inc', 'phone', 'include/phone.'. $countrycode);
if (function_exists($phone_info_function)) {
return $phone_info_function();
}
}
//Country not taken into account yet
return FALSE;
}
/**
* Verification for Phone Numbers.
*
* @param string $countrycode
* @param string $phonenumber
* @return boolean Returns boolean FALSE if the phone number is not valid.
*/
function valid_phone_number($countrycode, $phonenumber) {
$countrycode = trim($countrycode);
$phonenumber = trim($phonenumber);
if (phone_supported_countrycode($countrycode)) {
$valid_phone_function = 'valid_'. $countrycode . '_phone_number';
module_load_include('inc', 'phone', 'include/phone.'. $countrycode);
if (function_exists($valid_phone_function)) {
return $valid_phone_function($phonenumber);
}
}
//Country not taken into account yet
return FALSE;
}
/**
* Formatting for Phone Numbers.
*
* @param string $countrycode
* @param string $phonenumber
* @return boolean Returns boolean FALSE if the phone number is not valid.
*/
function format_phone_number($countrycode, $phonenumber, $field) {
$countrycode = trim($countrycode);
$phonenumber = trim($phonenumber);
if (phone_supported_countrycode($countrycode)) {
$format_phone_function = 'format_'. $countrycode . '_phone_number';
module_load_include('inc', 'phone', 'include/phone.'. $countrycode);
if (function_exists($format_phone_function)) {
return $format_phone_function($phonenumber, $field);
}
}
//Country not taken into account yet
return FALSE;
}

View File

@@ -0,0 +1,45 @@
<?php
class AUPhoneNumberTestCase extends DrupalWebTestCase {
/**
* Implementation of getInfo()
*
*/
public static function getInfo() {
return array(
'name' => t('Australia Phone number test'),
'description' => t('Tests various valid and invalid Australia phone numbers for validity'),
'group' => t('Phone')
);
}
public function testPhoneAUValid() {
$this->assertTrue(valid_phone_number('au', '0200-0299'), t('ACT - 0200-0299'));
$this->assertTrue(valid_phone_number('au', '2600-2639'), t('ACT - 2600-2639'));
$this->assertTrue(valid_phone_number('au', '1000-1999'), t('NSW - 1000-1999'));
$this->assertTrue(valid_phone_number('au', '2000-2599'), t('NSW - 2000-2599'));
$this->assertTrue(valid_phone_number('au', '2640-2914'), t('NSW - 2640-2914'));
$this->assertTrue(valid_phone_number('au', '0900-0999'), t('NT - 0900-0999'));
$this->assertTrue(valid_phone_number('au', '0800-0899'), t('NT - 0800-0899'));
$this->assertTrue(valid_phone_number('au', '9000-9999'), t('QLD - 9000-9999'));
$this->assertTrue(valid_phone_number('au', '4000-4999'), t('QLD - 4000-4999'));
$this->assertTrue(valid_phone_number('au', '5000-5999'), t('SA - 5000-599'));
$this->assertTrue(valid_phone_number('au', '7800-7999'), t('TAS - 7800-7999'));
$this->assertTrue(valid_phone_number('au', '7000-7499'), t('TAS - 7000-7499'));
$this->assertTrue(valid_phone_number('au', '8000-8999'), t('VIC - 8000-8999'));
$this->assertTrue(valid_phone_number('au', '3000-3999'), t('VIC - 3000-3999'));
$this->assertTrue(valid_phone_number('au', '6800-6999'), t('WA - 6800-6999'));
$this->assertTrue(valid_phone_number('au', '6000-6799'), t('WA - 6000-6799'));
}
public function testPhoneAUInvalid() {
$this->assertFalse(valid_phone_number('au', '0300'), t('Test invalid - 0300'));
$this->assertFalse(valid_phone_number('au', '7612'), t('Test invalid - 7612'));
$this->assertFalse(valid_phone_number('au', '2915'), t('Test invalid - 2915'));
$this->assertFalse(valid_phone_number('au', '2415b'), t('Test invalid - 2415b'));
}
public function testPhoneAUFormatting() {
//$this->assertEqual(format_phone_number('au', '+6421123456', null), '+64 21 123 456', t('Check international mobile format'));
}
}

View File

@@ -0,0 +1,31 @@
<?php
class BEPhoneNumberTestCase extends DrupalWebTestCase {
/**
* Implementation of getInfo()
*
*/
public static function getInfo() {
return array(
'name' => t('Belgium Phone number test'),
'description' => t('Tests various valid and invalid Belgium phone numbers for validity'),
'group' => t('Phone')
);
}
public function testPhoneBEValid() {
$this->assertTrue(valid_phone_number('be', '023456789'), '"023456789" should be valid');
$this->assertTrue(valid_phone_number('be', '0478990011'), '"0478990011" should be valid');
$this->assertTrue(valid_phone_number('be', '01 234 56 78'), '"01 234 56 78" should be valid');
$this->assertTrue(valid_phone_number('be', '+32 12345678'), '"+32 12345678" should be valid');
}
public function testPhoneBEInvalid() {
$this->assertFalse(valid_phone_number('be', '+323456789'), t('Test invalid'));
$this->assertFalse(valid_phone_number('be', '02 345 67 89'), t('Test invalid'));
}
public function testPhoneBEFormatting() {
//$this->assertEqual(format_phone_number('be', '+6421123456', null), '+64 21 123 456', t('Check international mobile format'));
}
}

View File

@@ -0,0 +1,39 @@
<?php
class BRPhoneNumberTestCase extends DrupalWebTestCase {
/**
* Implementation of getInfo()
*
*/
public static function getInfo() {
return array(
'name' => t('Brazil Phone number test'),
'description' => t('Tests various valid and invalid Brazil phone numbers for validity'),
'group' => t('Phone')
);
}
public function testPhoneBRValid() {
$this->assertTrue(valid_phone_number('br', '(11) 1234-5678'), t('Test valid - (11) 1234-5678'));
$this->assertTrue(valid_phone_number('br', '1234-5678 '), t('Test valid - 1234-5678'));
$this->assertTrue(valid_phone_number('br', '12345678'), t('Test valid - 12345678'));
$this->assertTrue(valid_phone_number('br', '+55 11 2222-3333'), t('Test valid - +55 11 2222-3333'));
$this->assertTrue(valid_phone_number('br', '011 5555-1234'), t('Test valid - 011 5555-1234'));
$this->assertTrue(valid_phone_number('br', '(011) 5555 1234'), t('Test valid - (011) 5555 1234'));
$this->assertTrue(valid_phone_number('br', '(11) 5555.1234'), t('Test valid - (11) 5555.1234'));
$this->assertTrue(valid_phone_number('br', '1155551234'), t('Test valid - 1155551234'));
}
public function testPhoneBRInvalid() {
$this->assertFalse(valid_phone_number('br', '123-45678'), t('Test invalid - 123-45678'));
$this->assertFalse(valid_phone_number('br', '(01) 5555 1234'), t('Test invalid - (01) 5555 1234'));
$this->assertFalse(valid_phone_number('br', '(11) 0555.1234'), t('Test invalid - (11) 0555.1234'));
$this->assertFalse(valid_phone_number('br', '(11) 5555 abcd'), t('Test invalid - (11) 5555 abcd'));
}
public function testPhoneBRFormatting() {
$this->assertEqual(format_br_phone_number('+55 11 2222-3333', null), '+55 (11) 222-333', t('Brazil - +55 (11) 222-333'));
}
}

View File

@@ -0,0 +1,32 @@
<?php
class CAPhoneNumberTestCase extends DrupalWebTestCase {
/**
* Implementation of getInfo()
*
*/
public static function getInfo() {
return array(
'name' => t('Canada & US Phone number test'),
'description' => t('Tests various valid and invalid Canada & US phone numbers for validity'),
'group' => t('Phone')
);
}
public function testPhoneCAValid() {
$this->assertTrue(valid_phone_number('ca', '1-800-555-1212'), t('Test valid - 1-800-555-1212'));
$this->assertTrue(valid_phone_number('ca', '800-555-1212'), t('Test valid - 800-555-1212'));
$this->assertTrue(valid_phone_number('ca', '(201)223-4567'), t('Test valid - (201)223-4567'));
$this->assertTrue(valid_phone_number('ca', '604 543 9245'), t('Test valid - British Columbia 604 543 9245'));
}
public function testPhoneCAInvalid() {
//$this->assertFalse(valid_phone_number('ca', '021 3012 3456'), t('Test invalid '));
}
public function testPhoneCAFormatting() {
//$this->assertEqual(format_phone_number('ca', '+6421123456', null), '+64 21 123 456', t('Check international mobile format'));
}
}

View File

@@ -0,0 +1,30 @@
<?php
class CHPhoneNumberTestCase extends DrupalWebTestCase {
/**
* Implementation of getInfo()
*
*/
public static function getInfo() {
return array(
'name' => t('Swiss Phone number test'),
'description' => t('Tests various valid and invalid Swiss phone numbers for validity'),
'group' => t('Phone')
);
}
public function testPhoneCHValid() {
//$this->assertTrue(valid_phone_number('ch', '04 476 0000'), t('Test valid'));
}
public function testPhoneCHInvalid() {
//$this->assertFalse(valid_phone_number('ch', '021 3012 3456'), t('Test invalid'));
}
public function testPhoneCHFormatting() {
//$this->assertEqual(format_phone_number('ch', '+6421123456', null), '+64 21 123 456', t('Check international mobile format'));
}
}

View File

@@ -0,0 +1,29 @@
<?php
class CLPhoneNumberTestCase extends DrupalWebTestCase {
/**
* Implementation of getInfo()
*
*/
public static function getInfo() {
return array(
'name' => t('Chili Phone number test'),
'description' => t('Tests various valid and invalid Chili phone numbers for validity'),
'group' => t('Phone')
);
}
public function testPhoneCLValid() {
$this->assertTrue(valid_phone_number('cl', '(041)245-9848'), t('Test valid'));
$this->assertTrue(valid_phone_number('cl', '(063)421-232'), t('Test valid'));
}
public function testPhoneCLInvalid() {
$this->assertFalse(valid_phone_number('cl', '0412459848'), t('Test invalid '));
$this->assertFalse(valid_phone_number('cl', '063421232'), t('Test invalid '));
}
public function testPhoneCLFormatting() {
//$this->assertEqual(format_phone_number('cl', '+6421123456', null), '+64 21 123 456', t('Check international mobile format'));
}
}

View File

@@ -0,0 +1,36 @@
<?php
class CNPhoneNumberTestCase extends DrupalWebTestCase {
/**
* Implementation of getInfo()
*
*/
public static function getInfo() {
return array(
'name' => t('China People\'s Republic Phone number test'),
'description' => t('Tests various valid and invalid Chinese People\'s Republic phone numbers for validity'),
'group' => t('Phone')
);
}
public function testPhoneCNValid() {
$this->assertTrue(valid_phone_number('cn', '86-755-83998006'), t('Test valid - 86-755-83998006'));
$this->assertTrue(valid_phone_number('cn', '86-10-5851 6688'), t('Test valid - 86-10-5851 6688'));
$this->assertTrue(valid_phone_number('cn', '86-10-6512 4940'), t('Test valid - 86-10-6512 4940'));
$this->assertTrue(valid_phone_number('cn', '+86 21 6103 2200'), t('Test valid - +86 21 6103 2200'));
$this->assertTrue(valid_phone_number('cn', '+86 10.85.32.83.23'), t('Test valid - +86 10.85.32.83.23'));
$this->assertTrue(valid_phone_number('cn', '755-83998006'), t('Test valid - 755-83998006'));
$this->assertTrue(valid_phone_number('cn', '+86-10-5851 6688'), t('Test valid - +86-10-5851 6688'));
$this->assertTrue(valid_phone_number('cn', '10.85.32.83.23'), t('Test valid - 10.85.32.83.23'));
$this->assertTrue(valid_phone_number('cn', '13900000000'), t('Test valid - 13900000000'));
$this->assertTrue(valid_phone_number('cn', '10-5851 6688'), t('Test valid - 10-5851 6688'));
}
public function testPhoneCNInvalid() {
//$this->assertFalse(valid_phone_number('cn', '021 3012 3456'), t('Test invalid - 021 3012 3456'));
}
public function testPhoneCNFormatting() {
//$this->assertEqual(format_phone_number('cn', '+6421123456', null), '+64 21 123 456', t('Check international mobile format'));
}
}

View File

@@ -0,0 +1,27 @@
<?php
class CRPhoneNumberTestCase extends DrupalWebTestCase {
/**
* Implementation of getInfo()
*
*/
public static function getInfo() {
return array(
'name' => t('Costa Rica Phone number test'),
'description' => t('Tests various valid and invalid Costa Rica phone numbers for validity'),
'group' => t('Phone')
);
}
public function testPhoneCRValid() {
//$this->assertTrue(valid_phone_number('cr', '04 476 0000'), t('Test valid'));
}
public function testPhoneCRInvalid() {
//$this->assertFalse(valid_phone_number('cr', '021 3012 3456'), t('Test invalid '));
}
public function testPhoneCRFormatting() {
//$this->assertEqual(format_phone_number('cr', '+6421123456', null), '+64 21 123 456', t('Check international mobile format'));
}
}

View File

@@ -0,0 +1,27 @@
<?php
class CSPhoneNumberTestCase extends DrupalWebTestCase {
/**
* Implementation of getInfo()
*
*/
public static function getInfo() {
return array(
'name' => t('Czech Republic Phone number test'),
'description' => t('Tests various valid and invalid Czech Republic phone numbers for validity'),
'group' => t('Phone')
);
}
public function testPhoneCSValid() {
$this->assertTrue(valid_phone_number('cs', '+420 999 999 999'), t('Test valid - +420 999 999 999'));
}
public function testPhoneCSInvalid() {
//$this->assertFalse(valid_phone_number('cs', '021 3012 3456'), t('Test invalid - 021 3012 3456'));
}
public function testPhoneCSFormatting() {
//$this->assertEqual(format_phone_number('cs', '+6421123456', null), '+64 21 123 456', t('Check international mobile format'));
}
}

View File

@@ -0,0 +1,27 @@
<?php
class EGPhoneNumberTestCase extends DrupalWebTestCase {
/**
* Implementation of getInfo()
*
*/
public static function getInfo() {
return array(
'name' => t('Egypt Phone number test'),
'description' => t('Tests various valid and invalid Egypt phone numbers for validity'),
'group' => t('Phone')
);
}
public function testPhoneEGValid() {
//$this->assertTrue(valid_phone_number('eg', '04 476 0000'), t('Test valid'));
}
public function testPhoneEGInvalid() {
//$this->assertFalse(valid_phone_number('eg', '021 3012 3456'), t('Test invalid '));
}
public function testPhoneEGFormatting() {
//$this->assertEqual(format_phone_number('eg', '+6421123456', null), '+64 21 123 456', t('Check international mobile format'));
}
}

View File

@@ -0,0 +1,32 @@
<?php
class ESPhoneNumberTestCase extends DrupalWebTestCase {
/**
* Implementation of getInfo()
*
*/
public static function getInfo() {
return array(
'name' => t('Spain Phone number test'),
'description' => t('Tests various valid and invalid Spain phone numbers for validity'),
'group' => t('Phone')
);
}
public function testPhoneESValid() {
$this->assertTrue(valid_phone_number('es', '972367087'), t('Test valid - 972367087'));
$this->assertTrue(valid_phone_number('es', '97-3770866'), t('Test valid - 97-3770866'));
$this->assertTrue(valid_phone_number('es', '972-377086'), t('Test valid - 972-377086'));
}
public function testPhoneESInvalid() {
$this->assertFalse(valid_phone_number('es', '9988-989898'), t('Test invalid - 9988-989898'));
$this->assertFalse(valid_phone_number('es', '989898988989'), t('Test invalid - 989898988989'));
$this->assertFalse(valid_phone_number('es', '9 9898989898'), t('Test invalid - 9 9898989898'));
}
public function testPhoneESFormatting() {
//$this->assertEqual(format_phone_number('es', '+6421123456', null), '+64 21 123 456', t('Check international mobile format'));
}
}

View File

@@ -0,0 +1,115 @@
<?php
// Copyright 2009 Thierry GUEGAN http://www.arvoriad.com
/**
/**
* Unit tests for Phone module.
*/
class PhoneFrenchTest extends DrupalWebTestCase {
public static function getInfo() {
return array(
'name' => t('France Phone number test'),
'description' => t('Executes test suite for validating / formatting France phone number.'),
'group' => t('Phone')
);
}
function setUp() {
parent::setUp();
include_once('./'. drupal_get_path('module', 'phone') .'/phone.fr.inc');
}
public function testPhoneFRValid() {
// test cleaning phone number
$this->assertTrue(valid_phone_number('fr', ' +33 123 45 - (67) 89'), "' +33 123 45 - (67) 89' should be valid");
$this->assertTrue(valid_phone_number('fr', '+33123456789'), "'+33123456789' should be valid");
$this->assertTrue(valid_phone_number('fr', '0123456789'), "'0123456789' should be valid");
$this->assertTrue(valid_phone_number('fr', '+33223456789'), "'+33223456789' should be valid");
$this->assertTrue(valid_phone_number('fr', '0223456789'), "'0223456789' should be valid");
$this->assertTrue(valid_phone_number('fr', '+33323456789'), "'+33323456789' should be valid");
$this->assertTrue(valid_phone_number('fr', '0323456789'), "'0323456789' should be valid");
$this->assertTrue(valid_phone_number('fr', '+33423456789'), "'+33423456789' should be valid");
$this->assertTrue(valid_phone_number('fr', '0423456789'), "'0423456789' should be valid");
$this->assertTrue(valid_phone_number('fr', '+33523456789'), "'+33523456789' should be valid");
$this->assertTrue(valid_phone_number('fr', '0523456789'), "'0523456789' should be valid");
// 06... mobile
$this->assertTrue(valid_phone_number('fr', '+33623456789'), "'+33623456789' should be valid");
$this->assertTrue(valid_phone_number('fr', '0623456789'), "'0623456789' should be valid");
// 085... virtual private network
$this->assertTrue(valid_phone_number('fr', '+33853456789'), "'+33853456789' should be valid");
$this->assertTrue(valid_phone_number('fr', '0853456789'), "'0853456789' should be valid");
// 087...
// 870... 871... 872... 873... 874... 875... 877... 878... 879... assigned
foreach (array('870', '871', '872', '873', '874', '875', '877', '878', '879') as $za) {
$this->assertTrue(valid_phone_number('fr', '+33'. $za .'123456'), "'+33 $za 1234567' is be valid");
$this->assertTrue(valid_phone_number('fr', '0'. $za .'123456'), "'0 $za 1234567' is be valid");
}
}
public function testPhoneFRInvalid() {
$this->assertFalse(valid_phone_number('fr', '+33 123456789a'), "'+33 123456789a' should not be valid because wrong char");
$this->assertFalse(valid_phone_number('fr', '+33 1234567a89'), "'+33 1234567a89' should not be valid because wrong char");
$this->assertFalse(valid_phone_number('fr', '0 123456789a'), "'0 123456789a' should not be valid because wrong char");
$this->assertFalse(valid_phone_number('fr', '0 1234567a89'), "'0 1234567a89' should not be valid because wrong char");
$this->assertFalse(valid_phone_number('fr', '+33 1234567890'), "'+33 1234567890' should not be valid because too long");
$this->assertFalse(valid_phone_number('fr', '+33 12345678'), "'+33 12345678' should not be valid because too short");
$this->assertFalse(valid_phone_number('fr', '0 1234567890'), "'0 1234567890' should not be valid because too long");
$this->assertFalse(valid_phone_number('fr', '0 12345678'), "'0 12345678' should not be valid because too short");
// 07... not assigned
$this->assertFalse(valid_phone_number('fr', '+33723456789'), "'+33723456789' is unassigned so should not be valid");
$this->assertFalse(valid_phone_number('fr', '0723456789'), "'0723456789' is unassigned so should not be valid");
// except 0876... not assigned
$this->assertFalse(valid_phone_number('fr', '+33876456789'), "'+33873456789' is unassigned so should not be valid");
$this->assertFalse(valid_phone_number('fr', '0876456789'), "'0873456789' is unassigned so should not be valid");
// 80... 81... 82... 83... 84... 86... 88... 89... not assigned
foreach (array('80', '81', '82', '83', '84', '86', '88', '89') as $za) {
$this->assertFalse(valid_phone_number('fr', '+33'. $za .'1234567'), "'+33'. $za .'1234567' is unassigned so should not be valid");
$this->assertFalse(valid_phone_number('fr', '0'. $za .'1234567'), "'0'. $za .'1234567' is unassigned so should not be valid");
}
// 09... not assigned
$this->assertFalse(valid_phone_number('fr', '+33923456789'), "'+33923456789' is unassigned so should not be valid");
$this->assertFalse(valid_phone_number('fr', '0923456789'), "'0923456789' is unassigned so should not be valid");
// 00... not assigned
$this->assertFalse(valid_phone_number('fr', '+33023456789'), "'+33023456789' is unassigned so should not be valid");
$this->assertFalse(valid_phone_number('fr', '0023456789'), "'0023456789' is unassigned so should not be valid");
}
public function testPhoneFRFormatting() {
// test cleaning phone number
$this->assertEqual(format_fr_phone_number('+33 123456789a'), '+33 123456789a', "'+33 123456789a', not valid so just ouptut without formatting");
$this->assertEqual(format_fr_phone_number('01234567a8'), '01234567a8', "'01234567a8', not valid so just ouptut without formatting");
$this->assertEqual(format_fr_phone_number('+33 123456789'), '0123456789', "international --> national");
$this->assertEqual(format_fr_phone_number(' +33 123 45 - (67) 89'), '0123456789', "international --> national");
$add_country_code = array('phone_country_code'=> TRUE);
$this->assertEqual(format_fr_phone_number('+33 123456789', $add_country_code), '+33 123456789', "international --> international");
$this->assertEqual(format_fr_phone_number(' +33 123 45 - (67) 89', $add_country_code), '+33 123456789', "international --> international");
}
}

View File

@@ -0,0 +1,38 @@
<?php
class HUPhoneNumberTestCase extends DrupalWebTestCase {
/**
* Implementation of getInfo()
*
*/
public static function getInfo() {
return array(
'name' => t('Hungary Phone number test'),
'description' => t('Tests various valid and invalid Hungary phone numbers for validity'),
'group' => t('Phone')
);
}
public function testPhoneHUValid() {
$this->assertTrue(valid_phone_number('hu', '+3611234567'), t('Test valid'));
$this->assertTrue(valid_phone_number('hu', '+3676123456'), t('Test valid'));
$this->assertTrue(valid_phone_number('hu', '+36301234567'), t('Test valid'));
$this->assertTrue(valid_phone_number('hu', '+36 1 1234567'), t('Test valid'));
$this->assertTrue(valid_phone_number('hu', '+36 76 123456'), t('Test valid'));
$this->assertTrue(valid_phone_number('hu', '+36 30 1234567'), t('Test valid'));
$this->assertTrue(valid_phone_number('hu', '+36(1)1234567'), t('Test valid'));
$this->assertTrue(valid_phone_number('hu', '+36(76)123456'), t('Test valid'));
$this->assertTrue(valid_phone_number('hu', '+36(30)1234567'), t('Test valid'));
$this->assertTrue(valid_phone_number('hu', '1/123-4567'), t('Test valid'));
$this->assertTrue(valid_phone_number('hu', '76/123-456'), t('Test valid'));
$this->assertTrue(valid_phone_number('hu', '30/123-45-67'), t('Test valid'));
}
public function testPhoneHUInvalid() {
$this->assertFalse(valid_phone_number('hu', '+0011234567'), t('Test invalid'));
}
public function testPhoneHUFormatting() {
//$this->assertEqual(format_phone_number('hu', '+6421123456', null), '+64 21 123 456', t('Check international mobile format'));
}
}

View File

@@ -0,0 +1,27 @@
<?php
class ILPhoneNumberTestCase extends DrupalWebTestCase {
/**
* Implementation of getInfo()
*
*/
public static function getInfo() {
return array(
'name' => t('Israel Phone number test'),
'description' => t('Tests various valid and invalid Israel phone numbers for validity'),
'group' => t('Phone')
);
}
public function testPhoneILValid() {
$this->assertTrue(valid_phone_number('il', '1800 999 999'), '"1800 999 999" should be valid');
}
public function testPhoneILInvalid() {
//$this->assertFalse(valid_phone_number('il', '021 3012 3456'), t('Test invalid'));
}
public function testPhoneILFormatting() {
$this->assertEqual(format_phone_number('il', '1800 999 999', null), '1800 999 999', 'Formatting OK "1800 999 999" --> "1800 999 999"');
}
}

View File

@@ -0,0 +1,94 @@
<?php
//require_once drupal_get_path('module', 'phone') . 'includes/phone.int.inc';
class PhoneIntTest extends DrupalWebTestCase {
public static function getInfo() {
return array(
'name' => 'International phone number test',
'description' => 'Tests international phone number validation.',
'group' => 'Phone',
);
}
public function setUp() {
// Enable the phone module.
parent::setUp(array('phone'));
}
private function assertConversion($input, $expect = TRUE, $field = array(), $expect_error = FALSE) {
$error = FALSE;
if (!isset($field['phone_int_max_length'])) {
$field['phone_int_max_length'] = '15';
}
if (!isset($field['phone_default_country_code'])) {
$field['phone_default_country_code'] = '1';
}
if ($expect === FALSE) {
$this->assertFalse(valid_phone_number('int', $input, $field, $error));
$this->assertIdentical($error, $expect_error);
return;
}
elseif ($expect === TRUE) {
$expect = $input;
}
$this->assertTrue(valid_phone_number('int', $input, $field, $error));
$this->assertIdentical($error, FALSE);
$result = format_phone_number('int', $input, $field);
$this->assertIdentical($result, $expect);
}
public function testBasic() {
$this->assertConversion('+1 7329018493');
}
public function testBasicWithThreeCountryCode() {
$this->assertConversion('+672 565434');
}
public function testBasicWithFourCountryCode() {
$this->assertConversion('+6724 565434', FALSE, array(), array(
'Invalid international phone number: Country code "+%cc" is too long; valid country codes are three digits or less.',
array('%cc' => '6724')
));
}
public function testBasicWithSpaces() {
$this->assertConversion('+1 732 901 8493');
}
public function testBasicNormalizeOtherCharacters() {
$this->assertConversion('+1 (732) 901-8493', '+1 732 901 8493');
}
public function testRemoveNDD() {
$this->assertConversion('+54 0435344', '+54 435344');
}
public function testRemoveNonStandardNDD() {
$this->assertConversion('+374 (8) 435344', '+374 435344');
}
public function testAddCountryCode() {
$this->assertConversion('732 343 2333', '+1 732 343 2333', array('phone_default_country_code' => '1'));
}
public function testOverlongNumber() {
$this->assertConversion('+123 456 789 012 3456', FALSE, array(),
'Invalid international phone number: Phone number is too long; international phone numbers are limited to 15 digits.'
);
}
public function testOverlongNumberWithoutCountryCode() {
$this->assertConversion('456 789 012 3456', FALSE, array('phone_default_country_code' => '123'),
'Invalid international phone number: Phone number is too long; international phone numbers are limited to 15 digits.'
);
}
public function testLetters() {
$this->assertConversion('+1 343 CALL US', FALSE, array(),
'Invalid international phone number: Phone number contains invalid characters; only allowed characters are numbers and punctuation.'
);
}
}

View File

@@ -0,0 +1,43 @@
<?php
class ITPhoneNumberTestCase extends DrupalWebTestCase {
/**
* Implementation of getInfo()
*
*/
public static function getInfo() {
return array(
'name' => t('Italia Phone number test'),
'description' => t('Tests various valid and invalid Italia phone numbers for validity'),
'group' => t('Phone')
);
}
public function testPhoneITValid() {
$this->assertTrue(valid_phone_number('it', '06/2034567'), t('Test valid - 06/2034567'));
$this->assertTrue(valid_phone_number('it', '+39 02/123456'), t('Test valid - +39 02/123456'));
$this->assertTrue(valid_phone_number('it', '02-343536'), t('Test valid - 02-343536'));
$this->assertTrue(valid_phone_number('it', '02/343536'), t('Test valid - 02/343536'));
$this->assertTrue(valid_phone_number('it', '02 343536'), t('Test valid - 02 343536'));
$this->assertTrue(valid_phone_number('it', '+393381234567'), t('Test valid - +393381234567'));
$this->assertTrue(valid_phone_number('it', '+39 3381234567'), t('Test valid - +39 3381234567'));
$this->assertTrue(valid_phone_number('it', '+39 338 1234567'), t('Test valid - +39 338 1234567'));
$this->assertTrue(valid_phone_number('it', '+39 338-1234567'), t('Test valid - +39 338-1234567'));
$this->assertTrue(valid_phone_number('it', '3381234567'), t('Test valid - 3381234567'));
$this->assertTrue(valid_phone_number('it', '3381234567'), t('Test valid - 3381234567'));
$this->assertTrue(valid_phone_number('it', '338 1234567'), t('Test valid - 338 1234567'));
$this->assertTrue(valid_phone_number('it', '338-1234567'), t('Test valid - 338-1234567'));
}
public function testPhoneITInvalid() {
$this->assertFalse(valid_phone_number('it', '02a343536'), t('Test invalid - 02a343536'));
$this->assertFalse(valid_phone_number('it', '02+343536'), t('Test invalid - 02+343536'));
$this->assertFalse(valid_phone_number('it', '0039 338 1234567'), t('Test invalid - 0039 338 1234567'));
$this->assertFalse(valid_phone_number('it', '(338)1234567'), t('Test invalid - (338)1234567'));
}
public function testPhoneITFormatting() {
//$this->assertEqual(format_phone_number('it', '+6421123456', null), '+64 21 123 456', t('Check international mobile format'));
}
}

View File

@@ -0,0 +1,27 @@
<?php
class JOPhoneNumberTestCase extends DrupalWebTestCase {
/**
* Implementation of getInfo()
*
*/
public static function getInfo() {
return array(
'name' => t('Jordania Phone number test'),
'description' => t('Tests various valid and invalid Jordania phone numbers for validity'),
'group' => t('Phone')
);
}
public function testPhoneJOValid() {
//$this->assertTrue(valid_phone_number('jo', '04 476 0000'), t('Test valid'));
}
public function testPhoneJOInvalid() {
//$this->assertFalse(valid_phone_number('jo', '021 3012 3456'), t('Test invalid'));
}
public function testPhoneJOFormatting() {
//$this->assertEqual(format_phone_number('jo', '+6421123456', null), '+64 21 123 456', t('Check international mobile format'));
}
}

View File

@@ -0,0 +1,27 @@
<?php
class NLPhoneNumberTestCase extends DrupalWebTestCase {
/**
* Implementation of getInfo()
*
*/
public static function getInfo() {
return array(
'name' => t('Netherland Phone number test'),
'description' => t('Tests various valid and invalid Netherland phone numbers for validity'),
'group' => t('Phone')
);
}
public function testPhoneNLValid() {
//$this->assertTrue(valid_phone_number('nl', '04 476 0000'), t('Test valid'));
}
public function testPhoneNLInvalid() {
//$this->assertFalse(valid_phone_number('nl', '021 3012 3456'), t('Test invalid '));
}
public function testPhoneNLFormatting() {
//$this->assertEqual(format_phone_number('nl', '+6421123456', null), '+64 21 123 456', t('Check international mobile format'));
}
}

View File

@@ -0,0 +1,68 @@
<?php
class NZPhoneNumberTestCase extends DrupalWebTestCase {
/**
* Implementation of getInfo()
*
*/
public static function getInfo() {
return array(
'name' => t('New Zealand Phone number test'),
'description' => t('Tests various valid and invalid New Zealand phone numbers for validity'),
'group' => t('Phone')
);
}
public function testPhoneNZValid() {
$this->assertTrue(valid_phone_number('nz', '04 476 0000'), t('Test standard regional number 04 476 0000'));
$this->assertTrue(valid_phone_number('nz', '+64 4 476 0000'), t('Test international variation of regional +64 4 476 0000'));
$this->assertTrue(valid_phone_number('nz', '+6444760000'), t('Test international variation of regional +6444760000'));
$this->assertTrue(valid_phone_number('nz', '+649302 0000'), t('Test slightly weird variation of international +649302 0000'));
$this->assertTrue(valid_phone_number('nz', '(04) 476 0000'), t('Test bracketed regional (04) 476 0000'));
$this->assertTrue(valid_phone_number('nz', '(04) 476-0000'), t('Test hyphenated regional (04) 476-0000'));
$this->assertTrue(valid_phone_number('nz', '03 903-1234'), t('Test valid South Island regional 03 903-1234'));
$this->assertTrue(valid_phone_number('nz', '021 123 456'), t('Test valid 8-digit Vodafone number 021 739 733'));
$this->assertTrue(valid_phone_number('nz', '(021) 123 456'), t('Test bracketed 8-digit Vodafone number (021) 739 733'));
$this->assertTrue(valid_phone_number('nz', '+6421123456'), t('Test international Vodafone +6421123456'));
$this->assertTrue(valid_phone_number('nz', '021 0101 2345'), t('Test 10-digit valid Vodafone number 021 2102 2345'));
$this->assertTrue(valid_phone_number('nz', '+642101012345'), t('Test international version 10-digit Vodafone +642121012345'));
$this->assertTrue(valid_phone_number('nz', '027 680 1234'), t('Test valid 9-digit Telecom Mobile number'));
$this->assertTrue(valid_phone_number('nz', '+64 27 680 1234'), t('Test valid international version of Telecom 9-digit +64 27 680 1234'));
$this->assertTrue(valid_phone_number('nz', '0800 83 83 83'), t('Test valid 0800 83 83 83 Pizza Hut'));
$this->assertTrue(valid_phone_number('nz', '0900 87687'), t('Test valid 0900 TROTS'));
$this->assertTrue(valid_phone_number('nz', '026 123 4567'), t('Test valid Telecom pager 026 123 4567'));
$this->assertTrue(valid_phone_number('nz', '022 123 4567'), t('Test valid NZ Comms mobile 022 123 4567'));
$this->assertTrue(valid_phone_number('nz', '22 123 4567'), t('Test slightly naughty lack of STD NZ Comms 22 123 4567'));
$this->assertTrue(valid_phone_number('nz', '020 123 4567'), t('Test valid Telecom Mobile Radio 020 123 4567'));
$this->assertTrue(valid_phone_number('nz', '029 123 4567'), t('Test valid TelstraClear Mobile Radio 029 123 4567'));
$this->assertTrue(valid_phone_number('nz', '+64 24 123 456'), t('Test valid Scott Base +64 24 123 456'));
}
public function testPhoneNZInvalid() {
$this->assertFalse(valid_phone_number('nz', '021 3012 3456'), t('Test invalid 10-digit Vodafone number in wrong range 021 3012 3456'));
$this->assertFalse(valid_phone_number('nz', '04 701 1234'), t('Test invalid Wellington regional number 04 701 1234'));
$this->assertFalse(valid_phone_number('nz', '(06) 412 3456'), t('Test invalid Manawatu regional number (06) 412 3456'));
$this->assertFalse(valid_phone_number('nz', '04 123 456'), t('Test too short Wellington regional number 04 123 456'));
$this->assertFalse(valid_phone_number('nz', '[04] 123 4567'), t('Test invalid character Wellington regional [04] 123 4567'));
$this->assertFalse(valid_phone_number('nz', '09 701 2345'), t('Test invalid Auckland regional 09 701 2345'));
$this->assertFalse(valid_phone_number('nz', '028 123 4567'), t('Test invalid mobile range 028 123 4567'));
$this->assertFalse(valid_phone_number('nz', '027 1234 5678'), t('Test invalid Telecom mobile length 027 1234 5678'));
}
public function testPhoneNZFormatting() {
$this->assertEqual(format_phone_number('nz', '+6421123456', null), '+64 21 123 456', t('Check international mobile format'));
$this->assertEqual(format_phone_number('nz', '021123456', null), '(021) 123 456', t('Check 6-digit domestic mobile format'));
$this->assertEqual(format_phone_number('nz', '0211234567', null), '(021) 123 4567', t('Check 7-digit domestic mobile format'));
$this->assertEqual(format_phone_number('nz', '+64211234567', null), '+64 21 123 4567', t('Check 7-digit international mobile format'));
$this->assertEqual(format_phone_number('nz', '02101234567', null), '(021) 0123 4567', t('Check 8-digit domestic mobile format'));
$this->assertEqual(format_phone_number('nz', '+642101234567', null), '+64 21 0123 4567', t('Check 8-digit international mobile format'));
$this->assertEqual(format_phone_number('nz', '041234567', null), '(04) 123 4567', t('Check regional number format (domestic)'));
$this->assertEqual(format_phone_number('nz', '+6441234567', null), '+64 4 123 4567', t('Check regional number format (international)'));
$this->assertEqual(format_phone_number('nz', '041234567x1234', null), '(04) 123 4567 x1234', t('Check regional number format with extension (domestic)'));
$this->assertEqual(format_phone_number('nz', '+6441234567x1234', null), '+64 4 123 4567 x1234', t('Check regional number format with extension (international)'));
$this->assertEqual(format_phone_number('nz', '0800 83 83 83', null), '0800 838383', t('Check 0800 number formatting (6 digit)'));
$this->assertEqual(format_phone_number('nz', '0800 123 4567', null), '0800 123 4567', t('Check 0800 number formatting (7 digit)'));
$this->assertEqual(format_phone_number('nz', '0800 12345', null), '0800 12345', t('Check 0800 number formatting (5 digit)'));
}
}

View File

@@ -0,0 +1,63 @@
<?php
class PhonePanamanianTest extends DrupalWebTestCase {
public static function getInfo() {
return array(
'name' => t('Panamanian phone'),
'description' => t('Executes test suite for validating / formatting Panamanian phone number.'),
'group' => t('Phone'),
);
}
function testValidatingPanamenianPhoneNumber() {
$this->assertTrue(valid_phone_number('pa', '+507 260-4334'), '+507 260-4334 should be valid');
$this->assertTrue(valid_phone_number('pa', '+507 2604334'), '+507 2604334 should be valid');
$this->assertTrue(valid_phone_number('pa', '+507 260 4334'), '+507 260 4334 should be valid');
$this->assertTrue(valid_phone_number('pa', '00507 2603133'), '00507 2603133 should be valid');
$this->assertTrue(valid_phone_number('pa', '00507 260-3133'), '00507 260-3133 should be valid');
$this->assertTrue(valid_phone_number('pa', '00507 260 4334'), '00507 260 4334 should be valid');
$this->assertTrue(valid_phone_number('pa', '260 3133'), '260 3133 should be valid');
$this->assertTrue(valid_phone_number('pa', '260-3133'), '260-3133 should be valid');
$this->assertTrue(valid_phone_number('pa', '2603133'), '2603133 should be valid');
//Cellphones
$this->assertTrue(valid_phone_number('pa', '+507 6545-4345'), '+507 6545-4345 should be valid');
$this->assertTrue(valid_phone_number('pa', '+507 65454345'), '+507 65454345 should be valid');
$this->assertTrue(valid_phone_number('pa', '+507 6545 4345'), '+507 6545 4345 should be valid');
$this->assertTrue(valid_phone_number('pa', '00507 6545-4345'), '00507 6545-4345 should be valid');
$this->assertTrue(valid_phone_number('pa', '00507 6545 4345'), '00507 6545 4345 should be valid');
$this->assertTrue(valid_phone_number('pa', '00507 65454345'), '00507 65454345 should be valid');
$this->assertTrue(valid_phone_number('pa', '6545-4345'), '6545-4345 should be valid');
$this->assertTrue(valid_phone_number('pa', '6545 4345'), '6545 4345 should be valid');
$this->assertTrue(valid_phone_number('pa', '65454345'), '65454345 should be valid');
//Invalid
$this->assertFalse(valid_phone_number('pa', '35343'), '35343 should not be valid');
$this->assertFalse(valid_phone_number('pa', '320-43'), '320-43 should not be valid');
$this->assertTrue(valid_phone_number('pa', '(507) 435-3434'), '(507) 435-3434 should not be valid');
}
function testFormattingPanamenianPhoneNumber() {
$this->assertEqual(format_phone_number('pa', '+507 260-4334'), '+507 260-4334', '+507 260-4334 format');
$this->assertEqual(format_phone_number('pa', '+507 2604334'), '+507 260-4334', '+507 2604334 format');
$this->assertEqual(format_phone_number('pa', '+507 260 4334'), '+507 260-4334', '+507 260 4334 format');
$this->assertEqual(format_phone_number('pa', '00507 260-4334'), '+507 260-4334', '00507 260-4334 format');
$this->assertEqual(format_phone_number('pa', '00507 2604334'), '+507 260-4334', '00507 2604334 format');
$this->assertEqual(format_phone_number('pa', '00507 260 4334'), '+507 260-4334', '00507 260 4334 format');
$this->assertEqual(format_phone_number('pa', '260-4334'), '260-4334', '260-4334 format');
$this->assertEqual(format_phone_number('pa', '2604334'), '260-4334', '2604334 format');
$this->assertEqual(format_phone_number('pa', '260 4334'), '260-4334', '260 4334 format');
$this->assertEqual(format_phone_number('pa', '260 4334', array('phone_country_code' => 1)), '+507 260-4334', 'add +507 to 260 4334 format');
//Cellphones
$this->assertEqual(format_phone_number('pa', '00507 6464 4334'), '+507 6464-4334', '6464 4334 format');
$this->assertEqual(format_phone_number('pa', '00507 6464-4334'), '+507 6464-4334', '00507 6464-4334 format');
$this->assertEqual(format_phone_number('pa', '00507 64644334'), '+507 6464-4334', '00507 64644334 format');
$this->assertEqual(format_phone_number('pa', '+507 6464 4334'), '+507 6464-4334', '+507 6464 4334 format');
$this->assertEqual(format_phone_number('pa', '6464 4334'), '6464-4334', '6464 4334 format');
$this->assertEqual(format_phone_number('pa', '64644334'), '6464-4334', '6464-4334 format');
$this->assertEqual(format_phone_number('pa', '6464 4334', array('phone_country_code' => 1)), '+507 6464-4334', 'add +507 to 6464 4334 format');
}
}

View File

@@ -0,0 +1,27 @@
<?php
class PHPhoneNumberTestCase extends DrupalWebTestCase {
/**
* Implementation of getInfo()
*
*/
public static function getInfo() {
return array(
'name' => t('Philippine Phone number test'),
'description' => t('Tests various valid and invalid Philippine phone numbers for validity'),
'group' => t('Phone')
);
}
public function testPhonePHValid() {
//$this->assertTrue(valid_phone_number('ph', '04 476 0000'), t('Test standard regional number 04 476 0000'));
}
public function testPhonePHInvalid() {
//$this->assertFalse(valid_phone_number('ph', '021 3012 3456'), t('Test invalid 10-digit Vodafone number in wrong range 021 3012 3456'));
}
public function testPhonePHFormatting() {
//$this->assertEqual(format_phone_number('ph', '+6421123456', null), '+64 21 123 456', t('Check international mobile format'));
}
}

View File

@@ -0,0 +1,31 @@
<?php
class PKPhoneNumberTestCase extends DrupalWebTestCase {
/**
* Implementation of getInfo()
*
*/
public static function getInfo() {
return array(
'name' => t('Pakistan Phone number test'),
'description' => t('Tests various valid and invalid Pakistan phone numbers for validity'),
'group' => t('Phone')
);
}
public function testPhonePKValid() {
$this->assertTrue(valid_phone_number('pk', '+92 321 7469854'), t('Test valid'));
$this->assertTrue(valid_phone_number('pk', '923217469857'), t('Test valid'));
$this->assertTrue(valid_phone_number('pk', '041 2680226'), t('Test valid'));
}
public function testPhonePKInvalid() {
$this->assertFalse(valid_phone_number('pk', '00124566'), t('Test invalid'));
$this->assertFalse(valid_phone_number('pk', '01 922 745689'), t('Test invalid'));
$this->assertFalse(valid_phone_number('pk', '0000000000'), t('Test invalid'));
}
public function testPhonePKFormatting() {
//$this->assertEqual(format_phone_number('pk', '+6421123456', null), '+64 21 123 456', t('Check international mobile format'));
}
}

View File

@@ -0,0 +1,32 @@
<?php
class PLPhoneNumberTestCase extends DrupalWebTestCase {
/**
* Implementation of getInfo()
*
*/
public static function getInfo() {
return array(
'name' => t('Poland Phone number test'),
'description' => t('Tests various valid and invalid Poland phone numbers for validity'),
'group' => t('Phone')
);
}
public function testPhonePLValid() {
$this->assertTrue(valid_phone_number('pl', '+48 500-080-100'), t('Test valid'));
$this->assertTrue(valid_phone_number('pl', '500080100'), t('Test valid'));
$this->assertTrue(valid_phone_number('pl', '500 080 100'), t('Test valid'));
}
public function testPhonePLInvalid() {
$this->assertFalse(valid_phone_number('pl', '+47 100-100-100'), t('Test invalid '));
$this->assertFalse(valid_phone_number('pl', '1000-100-100'), t('Test invalid '));
$this->assertFalse(valid_phone_number('pl', '1000000000'), t('Test invalid '));
}
public function testPhonePLFormatting() {
//$this->assertEqual(format_phone_number('pl', '+6421123456', null), '+64 21 123 456', t('Check international mobile format'));
}
}

View File

@@ -0,0 +1,33 @@
<?php
class RUPhoneNumberTestCase extends DrupalWebTestCase {
/**
* Implementation of getInfo()
*
*/
public static function getInfo() {
return array(
'name' => t('Russia Phone number test'),
'description' => t('Tests various valid and invalid Russia phone numbers for validity'),
'group' => t('Phone')
);
}
public function testPhoneRUValid() {
$this->assertTrue(valid_phone_number('ru', '+7(916)9985670'), t('Test valid'));
$this->assertTrue(valid_phone_number('ru', '8-912-268-5440'), t('Test valid'));
$this->assertTrue(valid_phone_number('ru', '8905148-3339'), t('Test valid'));
$this->assertTrue(valid_phone_number('ru', '8(913)448-51-90'), t('Test valid'));
$this->assertTrue(valid_phone_number('ru', '903-345-34-34'), t('Test valid'));
$this->assertTrue(valid_phone_number('ru', '903-34-334-34'), t('Test valid'));
$this->assertTrue(valid_phone_number('ru', '903-34-33434'), t('Test valid '));
}
public function testPhoneRUInvalid() {
$this->assertFalse(valid_phone_number('ru', '+33903-34-33434'), t('Test invalid '));
}
public function testPhoneRUFormatting() {
//$this->assertEqual(format_phone_number('ru', '+6421123456', null), '+64 21 123 456', t('Check international mobile format'));
}
}

View File

@@ -0,0 +1,43 @@
<?php
class SEPhoneNumberTestCase extends DrupalWebTestCase {
/**
* Implementation of getInfo()
*
*/
public static function getInfo() {
return array(
'name' => t('Sweden Phone number test'),
'description' => t('Tests various valid and invalid Sweden phone numbers for validity'),
'group' => t('Phone')
);
}
public function testPhoneSEValid() {
$this->assertTrue(valid_phone_number('se', '+46 8 123 456 78'), t('Test valid'));
$this->assertTrue(valid_phone_number('se', '08-123 456 78'), t('Test valid'));
$this->assertTrue(valid_phone_number('se', '0123-456 78'), t('Test valid'));
$this->assertTrue(valid_phone_number('se', '031-3224562'), t('Test valid'));
$this->assertTrue(valid_phone_number('se', '0737234264'), t('Test valid'));
$this->assertTrue(valid_phone_number('se', '073-5647829'), t('Test valid'));
$this->assertTrue(valid_phone_number('se', '19740609-7845'), t('Test valid'));
$this->assertTrue(valid_phone_number('se', '19811116-7845'), t('Test valid'));
$this->assertTrue(valid_phone_number('se', '20010913-7598'), t('Test valid'));
}
public function testPhoneSEInvalid() {
$this->assertFalse(valid_phone_number('se', '46 08-123 456 78'), t('Test invalid'));
$this->assertFalse(valid_phone_number('se', '08 123 456 78'), t('Test invalid '));
$this->assertFalse(valid_phone_number('se', '0123 456 78'), t('Test invalid '));
$this->assertFalse(valid_phone_number('se', '34348abc'), t('Test invalid'));
$this->assertFalse(valid_phone_number('se', '452643242343432432435643623432'), t('Test invalid '));
$this->assertFalse(valid_phone_number('se', '532'), t('Test invalid '));
$this->assertFalse(valid_phone_number('se', '21003612-9999'), t('Test invalid '));
$this->assertFalse(valid_phone_number('se', '18790505-45458'), t('Test invalid '));
$this->assertFalse(valid_phone_number('se', '19740641-5559'), t('Test invalid '));
}
public function testPhoneSEFormatting() {
//$this->assertEqual(format_phone_number('se', '+6421123456', null), '+64 21 123 456', t('Check international mobile format'));
}
}

View File

@@ -0,0 +1,40 @@
<?php
class SGPhoneNumberTestCase extends DrupalWebTestCase {
/**
* Implementation of getInfo()
*
*/
public static function getInfo() {
return array(
'name' => t('Singapore Phone number test'),
'description' => t('Tests various valid and invalid Singapore phone numbers for validity'),
'group' => t('Phone')
);
}
public function testPhoneSGValid() {
$this->assertTrue(valid_phone_number('sg', '61234567'), "'61234567' should be valid");
$this->assertTrue(valid_phone_number('sg', '63829324'), "'63829324' should be valid");
$this->assertTrue(valid_phone_number('sg', '67654321'), "'67654321' should be valid");
$this->assertTrue(valid_phone_number('sg', '+6561234567'), "'+6561234567' should be valid");
$this->assertTrue(valid_phone_number('sg', '+6581234567'), "'+6581234567' should be valid");
$this->assertTrue(valid_phone_number('sg', '+6591234567'), "'+6591234567' should be valid");
$this->assertTrue(valid_phone_number('sg', '+65 61234567'), "'+65 61234567' should be valid");
$this->assertTrue(valid_phone_number('sg', '+65 81234567'), "'+65 81234567' should be valid");
$this->assertTrue(valid_phone_number('sg', '+65 91234567'), "'+65 91234567' should be valid");
$this->assertTrue(valid_phone_number('sg', '61234567'), "'61234567' should be valid");
$this->assertTrue(valid_phone_number('sg', '81234567'), "'81234567' should be valid");
$this->assertTrue(valid_phone_number('sg', '91234567'), "'91234567' should be valid");
}
public function testPhoneSGInvalid() {
$this->assertFalse(valid_phone_number('sg', '6123-4567'), t('Test invalid '));
$this->assertFalse(valid_phone_number('sg', '6-CALL-CPY'), t('Test invalid '));
$this->assertFalse(valid_phone_number('sg', '6123abcd'), t('Test invalid '));
}
public function testPhoneSGFormatting() {
//$this->assertEqual(format_phone_number('sg', '+6421123456', null), '+64 21 123 456', t('Check international mobile format'));
}
}

View File

@@ -0,0 +1,43 @@
<?php
class UAPhoneNumberTestCase extends DrupalWebTestCase {
/**
* Implementation of getInfo()
*
*/
public static function getInfo() {
return array(
'name' => t('Ukraine Phone number test'),
'description' => t('Tests various valid and invalid Ukraine phone numbers for validity'),
'group' => t('Phone')
);
}
function setUp() {
parent::setUp();
}
public function testPhoneUAValid() {
$this->assertTrue(valid_phone_number('ua', '+38-044-283-93-57'), t('Kyiv landline test'));
$this->assertTrue(valid_phone_number('ua', '(044)2839357'), t('Kyiv landline test'));
$this->assertTrue(valid_phone_number('ua', '+380442839357'), t('Kyiv landline test'));
$this->assertTrue(valid_phone_number('ua', '+38 (044)537-28-07'), t('Kyiv landline test'));
$this->assertTrue(valid_phone_number('ua', '044 537-28-07'), t('Kyiv landline test'));
$this->assertTrue(valid_phone_number('ua', '+38 032 2724042 '), t('Lviv landline test'));
$this->assertTrue(valid_phone_number('ua', '+380623621047'), t('Yasinovata landline test'));
}
public function testPhoneUAInvalid() {
$this->assertFalse(valid_phone_number('ua', '+380117777777'), t('Test with noexist citycode 011'));
$this->assertFalse(valid_phone_number('ua', '+380711234567'), t('Test with noexist citycode 071'));
$this->assertFalse(valid_phone_number('ua', '+38044123456'), t('Test with short phone'));
$this->assertFalse(valid_phone_number('ua', '044123456'), t('Test with short phone'));
$this->assertFalse(valid_phone_number('ua', '+3804412345678'), t('Test with long phone'));
$this->assertFalse(valid_phone_number('ua', '04412345678'), t('Test with long phone'));
$this->assertFalse(valid_phone_number('ua', '8044223-95-26'), t('Test with obsolete leading 8 notation'));
}
public function testPhoneUAFormatting() {
//$this->assertEqual(format_phone_number('ua', '+6421123456', null), '+64 21 123 456', t('Check international mobile format'));
}
}

View File

@@ -0,0 +1,41 @@
<?php
class UKPhoneNumberTestCase extends DrupalWebTestCase {
/**
* Implementation of getInfo()
*
*/
public static function getInfo() {
return array(
'name' => t('UK Phone number test'),
'description' => t('Tests various valid and invalid UK phone numbers for validity'),
'group' => t('Phone')
);
}
public function testPhoneUKValid() {
$this->assertTrue(valid_phone_number('uk', '01905 23819'), t('Test valid - 01905 23819'));
$this->assertTrue(valid_phone_number('uk', '01222 555 555'), t('Test valid - 01222 555 555'));
$this->assertTrue(valid_phone_number('uk', '(010) 55555555 #2222'), t('Test valid - (010) 55555555 #2222'));
$this->assertTrue(valid_phone_number('uk', '0122 555 5555#222'), t('Test valid - 0122 555 5555#222'));
$this->assertTrue(valid_phone_number('uk', '+441970123456'), t('Test valid - +441970123456'));
$this->assertTrue(valid_phone_number('uk', '+44(0)1970123456'), t('Test valid - +44(0)1970123456'));
$this->assertTrue(valid_phone_number('uk', '+44 1970 123 4562'), t('Test valid - +44 1970 123 456'));
$this->assertTrue(valid_phone_number('uk', '+44 (0)1970 123 456'), t('Test valid - +44 (0)1970 123 456'));
$this->assertTrue(valid_phone_number('uk', '(01970) 123456 #0001'), t('Test valid - (01970) 123456 #0001'));
}
public function testPhoneUKInvalid() {
$this->assertFalse(valid_phone_number('uk', '01222 555 5555'), t('Test invalid - 01222 555 5555'));
$this->assertFalse(valid_phone_number('uk', '(010) 55555555 #22'), t('Test invalid - (010) 55555555 #22'));
$this->assertFalse(valid_phone_number('uk', '0122 5555 5555#222'), t('Test invalid - 0122 5555 5555#222'));
$this->assertFalse(valid_phone_number('uk', '(+441970)123456'), t('Test invalid - (+441970)123456'));
$this->assertFalse(valid_phone_number('uk', '+44(1970)123456'), t('Test invalid - +44(1970)123456'));
$this->assertFalse(valid_phone_number('uk', '+44 01970 123 456'), t('Test invalid - +44 01970 123 456'));
$this->assertFalse(valid_phone_number('uk', '(0197) 0123456 #01'), t('Test invalid - (0197) 0123456 #01'));
}
public function testPhoneUKFormatting() {
//$this->assertEqual(format_phone_number('uk', '+6421123456', null), '+64 21 123 456', t('Check international mobile format'));
}
}

View File

@@ -0,0 +1,46 @@
<?php
class ZAPhoneNumberTestCase extends DrupalWebTestCase {
/**
* Implementation of getInfo()
*
*/
public static function getInfo() {
return array(
'name' => t('South Africa Phone number test'),
'description' => t('Tests various valid and invalid South African phone numbers for validity'),
'group' => t('Phone')
);
}
public function testPhoneZAValid() {
$this->assertTrue(valid_phone_number('za', '+27 11 888-8888'), t('Test valid - +27 11 888-8888'));
$this->assertTrue(valid_phone_number('za', '0333872119'), t('Test valid - 0333872119'));
$this->assertTrue(valid_phone_number('za', '074 101 2850'), t('Test valid - 074 101 2850'));
$this->assertTrue(valid_phone_number('za', '27723376484'), t('Test valid - 27723376484'));
$this->assertTrue(valid_phone_number('za', '0723376484'), t('Test valid - 0723376484'));
$this->assertTrue(valid_phone_number('za', '0111231234'), t('Test valid - 0111231234'));
$this->assertTrue(valid_phone_number('za', '011 123 1234'), t('Test valid - 011 123 1234'));
$this->assertTrue(valid_phone_number('za', '011-123-1234'), t('Test valid - 011-123-1234'));
$this->assertTrue(valid_phone_number('za', '0821231234'), t('Test valid - 0821231234'));
$this->assertTrue(valid_phone_number('za', '082 123 1234'), t('Test valid - 082 123 1234'));
$this->assertTrue(valid_phone_number('za', '+27821231234'), t('Test valid - +27821231234'));
$this->assertTrue(valid_phone_number('za', '+2782-123-1234'), t('Test valid - +2782-123-1234'));
$this->assertTrue(valid_phone_number('za', '+2782 123 1234'), t('Test valid - +2782 123 1234'));
$this->assertTrue(valid_phone_number('za', '27111231234'), t('Test valid - 27111231234'));
$this->assertTrue(valid_phone_number('za', '2711 123 1234'), t('Test valid - 2711 123 1234'));
$this->assertTrue(valid_phone_number('za', '082 123 1234'), t('Test valid - 082 123 1234'));
}
public function testPhoneZAInvalid() {
$this->assertFalse(valid_phone_number('za', '9723376484'), t('Test invalid - 9723376484'));
$this->assertFalse(valid_phone_number('za', '26723376484'), t('Test invalid - 26723376484'));
$this->assertFalse(valid_phone_number('za', '(011)1231234'), t('Test invalid - (011)1231234'));
$this->assertFalse(valid_phone_number('za', '(+2711) 123 1234'), t('Test invalid - (+2711) 123 1234'));
$this->assertFalse(valid_phone_number('za', '(011) 123-1234'), t('Test invalid - (011) 123-1234'));
}
public function testPhoneZAFormatting() {
$this->assertEqual(format_phone_number('za', '082 123 1234', null), '082 123 1234', 'Formatting OK "082 123 1234" --> "082 123 1234"');
}
}

View File

@@ -0,0 +1,5 @@
/* prevent input fields from being set to a percentage, such as 95% */
div.form-item input.phone-field-textfield {
width: auto;
}

View File

@@ -0,0 +1,37 @@
Webform 2.x Changelog
---------------------
2.x to 3.0
----------
- Module directory structure moved around.
- Webform configuration moved to an entirely separate tab.
- E-mail templates are now editable by administrators.
- Conditional fields.
- Submissions may be saved as a draft and resumed later.
- Webform may now be attached to any content type.
- Public API for allowing other modules to provide components.
- Public API for interacting with submission save, insert, update, and delete.
- New rendering capabilities for HTML presentation of submissions and e-mails.
- Print module support.
- Basic Views module support.
- Popup calendar support on Date components (with Date Popup module).
- New Mollom module integration.
1.x to 2.0
----------
- Redirect POST option removed.
- Webform components moved to the "Form components" tab when editing.
- Webform node structure changed. All webform additions to the node are placed in $node->webform.
- Clone option added to components.
- Database storage improved to be more consistent and efficient.
- Additional e-mails may be sent by modifying the $node->webform['additional_emails'] variable in the Additional Validation field.
- The values of select and hidden fields may receive e-mails by using the option in Conditional e-mail recipients field.
- E-mail from name, from address, and from subject may be entered in a text field.
- The complete webform may be shown in the teaser view of a node.
- Submit button text may be changed.
- Theme function theme_webform_create_mailmessage() has been renamed to theme_webform_mail_message().
- $cid parameter added to theme_webform_mail_message() to create unique e-mails depending on a particular recipient or component.
- Theme function theme_webform_mail_headers added.
- Component descriptions are textareas rather than textfields.
- _webform_filtervalues() has been renamed to _webform_filter_values.

View File

@@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

View File

@@ -0,0 +1,41 @@
Description
-----------
This module adds a webform content type to your Drupal site.
A webform can be a questionnaire, contact or request form. These can be used
by visitor to make contact or to enable a more complex survey than polls
provide. Submissions from a webform are saved in a database table and
can optionally be mailed to e-mail addresses upon submission.
Requirements
------------
Drupal 7.x
Installation
------------
1. Copy the entire webform directory the Drupal sites/all/modules directory.
2. Login as an administrator. Enable the module in the "Administer" -> "Modules"
3. (Optional) Edit the settings under "Administer" -> "Configuration" ->
"Content authoring" -> "Webform settings"
4. Create a webform node at node/add/webform.
Upgrading from previous versions
--------------------------------
Note that if you are upgrading from a Drupal 6 installation of Webform, you MUST
have been running Webform 3.x on your Drupal 6 site before upgrading to Drupal
7 and Webform 3.x. You cannot upgrade directly from Webform 6.x-2.x to Webform
7.x-3.x.
1. Copy the entire webform directory the Drupal modules directory.
2. Login as the FIRST user or change the $access_check in update.php to FALSE
3. Run update.php (at http://www.example.com/update.php)
Support
-------
Please use the issue queue for filing bugs with this module at
http://drupal.org/project/issues/webform

View File

@@ -0,0 +1,115 @@
Overview
--------
Webform supports theming similar to the CCK or Views modules. Any webform
may be themed on the server side, though doing so may require a reasonable
amount of knowledge about the Drupal Form API. More information about the Form
API may be found at http://api.drupal.org/api/file/developer/topics/forms_api.html
Theme submission e-mails
-----------------------
The default e-mails sent by webform are fairly basic. If you like, you may
customize the display of e-mails sent by each individual webform.
- Open the Webform module directory.
- Copy (do not move!) the "webform-mail.tpl.php" file to your theme directory.
- Open up the new file and edit it to your liking. The webform-mail.tpl.php file
contains further instructions on how to get started with theming the e-mail.
- If you want to edit the e-mail sent by only one particular webform, rename the
file "webform-mail-[node id here].tpl.php", replacing [node id here] with the
node ID of the webform.
- Clear the theme cache! Visit admin/settings/performance and click the
"Clear cached data" button at the bottom of the page. You may also find
using devel module will speed up this process a bit. This needs to be done
every time you create or rename a .tpl.php file, but isn't necessary once
these files already exist.
- To get a better idea of what variables are available to you, you can include
the print_r function in your email. Simply include the line:
<?php print_r($submission) ?>
to get a listing of all the available fields you can use in your mail.
- Advanced Webform e-mail Theming: Theming the e-mail headers may also be done
by overriding the theme_webform_mail_headers() function from webform.module.
Just copy the code out of webform.module and change as necessary in your
template.php file. This allows you to customize the e-mail headers.
Theme the confirmation page
---------------------------
After a user submits a webform, they are directed to a page that contains the
confirmation message set in the webform node settings (assuming the form doesn't
direct to a complete URL). These instructions let you customize the format of
the confirmation page of a single node or all webforms on your site.
- Open the Webform module directory.
- Copy (do not move!) the "webform-confirmation.tpl.php" file to your theme
directory.
- Open the new file and change it's contents to the your liking. Here's an
example that inserts some additional HTML around the confirmation message and
gives links to edit the submission.
<?php /* Begin sample webform confirmation page */ ?>
<div class="confirmation-message">
<?php print $confirmation_message ?>
</div>
<ul>
<li><a href="<?php print url('node/'. $node->nid . '/submission/'. $sid)?>">View your submission</a></li>
<li><a href="<?php print url('node/'. $node->nid . '/submission/'. $sid .'/edit')?>">Edit your submission</a></li>
</ul>
<?php /* End sample webform confirmation page */ ?>
- You may edit the webform-confirmation.tpl.php file in your theme directory,
this will affect all the webform mails sent by your entire site. Or, if you
want to edit the e-mail sent by only one particular webform, rename the file
"webform-confirmation-[node id here].tpl.php", replacing [node id here] with
the node ID of the webform.
- Visit admin/settings/performance and click the "Clear cached data" button.
Theme display of an entire webform
----------------------------------
Theming a webform can be useful for rearranging elements or customizing the
appearance of multiple components at once. This tutorial assumes usage
of the phptemplate engine.
- Copy the "webform-form.tpl.php" file from the webform directory to your
theme directory. You may rename this file
"webform-form-[node id here].tpl.php" if you want to theme one particular
webform on your site. Replace [node id here] with the node ID of the webform.
- Open up your new file and customize the webform however you like.
- Visit admin/settings/performance and click the "Clear cached data" button.
- All Webform forms have 2 main fieldsets: "submitted", and "details". Although
you may move things around as you wish, keep all your components within the
"submitted" fieldset. Only the "submitted" fieldset is displayed and Webform
depends on the other two to operate properly, so don't mess with them unless
you have good reason to do so (like you're forwarding your webform to a custom
PHP or PERL script).
Theme display of a webform submission display
---------------------------------------------
Theming the display of a webform submission works the same way as theming a
webform form. Webform uses Drupal "renderable" style arrays for the display of
submissions, just like most forms in Drupal.
The template file for theming submissions is webform-submission.tpl.php. You can
use webform-submission-[node id here].tpl.php for individual nodes if desired.
Note that the contents of this template are used not only for display of
submissions in the Webform interface but also in e-mails when printing out
the %email_values token.

View File

@@ -0,0 +1,433 @@
<?php
/**
* @file
* Webform module date component.
*/
/**
* Implements _webform_defaults_component().
*/
function _webform_defaults_date() {
return array(
'name' => '',
'form_key' => NULL,
'pid' => 0,
'weight' => 0,
'value' => '',
'mandatory' => 0,
'extra' => array(
'timezone' => 'user',
'start_date' => '-2 years',
'end_date' => '+2 years',
'year_textfield' => 0,
'datepicker' => 1,
'title_display' => 0,
'description' => '',
'private' => FALSE,
),
);
}
/**
* Implements _webform_theme_component().
*/
function _webform_theme_date() {
return array(
'webform_date' => array(
'render element' => 'element',
'file' => 'components/date.inc',
),
'webform_display_date' => array(
'render element' => 'element',
'file' => 'components/date.inc',
),
'webform_calendar' => array(
'variables' => array('component' => NULL, 'calendar_classes' => NULL),
'template' => 'templates/webform-calendar',
),
);
}
/**
* Implements _webform_edit_component().
*/
function _webform_edit_date($component) {
$form = array();
$form['value'] = array(
'#type' => 'textfield',
'#title' => t('Default value'),
'#default_value' => $component['value'],
'#description' => t('The default value of the field.') . '<br />' . t('Accepts any date in any <a href="http://www.gnu.org/software/tar/manual/html_chapter/Date-input-formats.html">GNU Date Input Format</a>. Strings such as today, +2 months, and Dec 9 2004 are all valid.'),
'#size' => 60,
'#maxlength' => 127,
'#weight' => 0,
);
$form['extra']['timezone'] = array(
'#type' => 'radios',
'#title' => t('Default value timezone'),
'#default_value' => empty($component['extra']['timezone']) ? 'user' : $component['extra']['timezone'],
'#description' => t('If using relative dates for a default value (e.g. "today") base the current day on this timezone.'),
'#options' => array('user' => t('User timezone'), 'site' => t('Website timezone')),
'#weight' => 2,
'#access' => variable_get('configurable_timezones', 1),
);
$form['display']['datepicker'] = array(
'#type' => 'checkbox',
'#title' => t('Enable popup calendar'),
'#default_value' => $component['extra']['datepicker'],
'#description' => t('Enable a JavaScript date picker next to the date field.'),
'#weight' => 2,
'#parents' => array('extra', 'datepicker'),
);
$form['display']['year_textfield'] = array(
'#type' => 'checkbox',
'#title' => t('Use a textfield for year'),
'#default_value' => $component['extra']['year_textfield'],
'#description' => t('If checked, the generated date field will use a textfield for the year. Otherwise it will use a select list.'),
'#weight' => 5,
'#parents' => array('extra', 'year_textfield'),
);
$form['validation']['start_date'] = array(
'#type' => 'textfield',
'#title' => t('Start date'),
'#default_value' => $component['extra']['start_date'],
'#description' => t('The earliest date that may be entered into the field.') . ' ' . t('Accepts any date in any <a href="http://www.gnu.org/software/tar/manual/html_chapter/Date-input-formats.html">GNU Date Input Format</a>.'),
'#size' => 30,
'#weight' => 3,
'#parents' => array('extra', 'start_date'),
);
$form['validation']['end_date'] = array(
'#type' => 'textfield',
'#title' => t('End date'),
'#default_value' => $component['extra']['end_date'],
'#description' => t('The latest date that may be entered into the field.') . ' ' . t('Accepts any date in any <a href="http://www.gnu.org/software/tar/manual/html_chapter/Date-input-formats.html">GNU Date Input Format</a>.'),
'#size' => 30,
'#weight' => 4,
'#parents' => array('extra', 'end_date'),
);
return $form;
}
/**
* Implements _webform_render_component().
*/
function _webform_render_date($component, $value = NULL, $filter = TRUE) {
$node = isset($component['nid']) ? node_load($component['nid']) : NULL;
$element = array(
'#type' => 'date',
'#title' => $filter ? _webform_filter_xss($component['name']) : $component['name'],
'#title_display' => $component['extra']['title_display'] ? $component['extra']['title_display'] : 'before',
'#weight' => $component['weight'],
'#description' => $filter ? _webform_filter_descriptions($component['extra']['description'], $node) : $component['extra']['description'],
'#required' => $component['mandatory'],
'#start_date' => trim($component['extra']['start_date']),
'#end_date' => trim($component['extra']['end_date']),
'#year_textfield' => $component['extra']['year_textfield'],
'#default_value' => $filter ? _webform_filter_values($component['value'], $node, NULL, NULL, FALSE) : $component['value'],
'#timezone' => $component['extra']['timezone'],
'#process' => array('webform_expand_date'),
'#theme' => 'webform_date',
'#theme_wrappers' => array('webform_element'),
'#element_validate' => array('webform_validate_date'),
'#translatable' => array('title', 'description'),
);
if ($component['extra']['datepicker']) {
$element['#datepicker'] = TRUE;
$element['#attached'] = array(
'library' => array(
array('system', 'ui.datepicker'),
),
);
}
// Set the value from Webform.
if (isset($value[0]) && $value[0] !== '') {
$value = webform_date_array($value[0], 'date');
$element['#default_value'] = $value;
}
return $element;
}
/**
* Form API #process function for Webform date fields.
*/
function webform_expand_date($element) {
// Accept a string or array value for #default_value.
if (!empty($element['#default_value']) && is_string($element['#default_value'])) {
$timezone = $element['#timezone'] != 'user' ? NULL : 'user';
$timestring = webform_strtodate('c', $element['#default_value'], $timezone);
$element['#default_value'] = webform_date_array($timestring, 'date');
}
// Set defaults according to existing #default_value (set by Form API)
if (isset($element['#default_value']['month']) || isset($element['#default_value']['day']) || isset($element['#default_value']['year'])) {
$default_values = array(
'month' => $element['#default_value']['month'],
'day' => $element['#default_value']['day'],
'year' => $element['#default_value']['year'],
);
}
else {
$default_values = array(
'day' => NULL,
'month' => NULL,
'year' => NULL,
);
}
// Let Drupal do it's normal expansion.
$element = form_process_date($element);
// Set default values.
foreach ($default_values as $type => $value) {
switch ($type) {
case 'month':
$none = t('Month');
break;
case 'day':
$none = t('Day');
break;
case 'year':
$none = t('Year');
break;
}
unset($element[$type]['#value']);
$element[$type]['#default_value'] = isset($default_values[$type]) ? $default_values[$type] : NULL;
$element[$type]['#options'] = array('' => $none) + $element[$type]['#options'];
}
// Convert relative dates to absolute ones.
foreach (array('start_date', 'end_date') as $start_end) {
$timezone = $element['#timezone'] != 'user' ? NULL : 'user';
$date = webform_strtodate('Y-m-d', $element['#' . $start_end], $timezone);
$element['#' . $start_end] = $date ? $date : '';
}
// Tweak the year field.
if ($element['#year_textfield']) {
$element['year']['#type'] = 'textfield';
$element['year']['#size'] = 5;
$element['year']['#maxlength'] = 4;
unset($element['year']['#options']);
}
elseif ($element['#start_date'] || $element['#end_date']) {
$start_year = $element['#start_date'] ? webform_strtodate('Y', $element['#start_date']) : webform_strtodate('Y', '-2 years');
$end_year = $element['#end_date'] ? webform_strtodate('Y', $element['#end_date']) : webform_strtodate('Y', '+2 years');
$element['year']['#options'] = array('' => t('Year')) + drupal_map_assoc(range($start_year, $end_year));
}
return $element;
}
/**
* Theme a webform date element.
*/
function theme_webform_date($variables) {
$element = $variables['element'];
$element['year']['#attributes']['class'] = array('year');
$element['month']['#attributes']['class'] = array('month');
$element['day']['#attributes']['class'] = array('day');
// Add error classes to all items within the element.
if (form_get_error($element)) {
$element['year']['#attributes']['class'][] = 'error';
$element['month']['#attributes']['class'][] = 'error';
$element['day']['#attributes']['class'][] = 'error';
}
$class = array('webform-container-inline');
// Add the JavaScript calendar if available (provided by Date module package).
if (!empty($element['#datepicker'])) {
$class[] = 'webform-datepicker';
$calendar_class = array('webform-calendar');
if ($element['#start_date']) {
$calendar_class[] = 'webform-calendar-start-' . $element['#start_date'];
}
if ($element['#end_date']) {
$calendar_class[] = 'webform-calendar-end-' . $element['#end_date'];
}
$calendar_class[] ='webform-calendar-day-' . variable_get('date_first_day', 0);
$calendar = theme('webform_calendar', array('component' => $element['#webform_component'], 'calendar_classes' => $calendar_class));
}
$output = '';
$output .= '<div class="' . implode(' ', $class) . '">';
$output .= drupal_render_children($element);
$output .= isset($calendar) ? $calendar : '';
$output .= '</div>';
return $output;
}
/**
* Element validation for Webform date fields.
*/
function webform_validate_date($element, $form_state) {
// Check if the user filled the required fields.
foreach (array('day', 'month', 'year') as $field_type) {
if (!is_numeric($element[$field_type]['#value']) && $element['#required']) {
form_error($element, t('!name field is required.', array('!name' => $element['#title'])));
return;
}
}
if ($element['month']['#value'] !== '' || $element['day']['#value'] !== '' || $element['year']['#value'] !== '') {
// Check for a valid date.
if (!checkdate((int) $element['month']['#value'], (int) $element['day']['#value'], (int) $element['year']['#value'])) {
form_error($element, t('Entered !name is not a valid date.', array('!name' => $element['#title'])));
return;
}
// Create a timestamp of the entered value for comparison.
$timestamp = strtotime($element['year']['#value'] . '-' . $element['month']['#value'] . '-' . $element['day']['#value']);
$format = webform_date_format('short');
// Flip start and end if needed.
$date1 = strtotime($element['#start_date']);
$date2 = strtotime($element['#end_date']);
if ($date1 !== FALSE && $date2 !== FALSE) {
$start_date = $date1 < $date2 ? $date1 : $date2;
$end_date = $date1 > $date2 ? $date1 : $date2;
}
else {
$start_date = $date1;
$end_date = $date2;
}
// Check that the date is after the start date.
if ($start_date !== FALSE) {
if ($timestamp < $start_date) {
form_error($element, t('The entered date must be @start_date or later.', array('@start_date' => date($format, $start_date))));
}
}
// Check that the date is before the end date.
if ($end_date !== FALSE) {
if ($timestamp > $end_date) {
form_error($element, t('The entered date must be @end_date or earlier.', array('@end_date' => date($format, $end_date))));
}
}
}
}
/**
* Implements _webform_submit_component().
*/
function _webform_submit_date($component, $value) {
// Convert the date to an ISO 8601 format.
return ($value['year'] && $value['month'] && $value['day']) ? webform_date_string($value, 'date') : '';
}
/**
* Implements _webform_display_component().
*/
function _webform_display_date($component, $value, $format = 'html') {
$value = webform_date_array(isset($value[0]) ? $value[0] : '', 'date');
return array(
'#title' => $component['name'],
'#weight' => $component['weight'],
'#theme' => 'webform_display_date',
'#theme_wrappers' => $format == 'html' ? array('webform_element') : array('webform_element_text'),
'#format' => $format,
'#value' => $value,
'#translatable' => array('title'),
);
}
/**
* Format the text output for this component.
*/
function theme_webform_display_date($variables) {
$element = $variables['element'];
$output = ' ';
if ($element['#value']['year'] && $element['#value']['month'] && $element['#value']['day']) {
$timestamp = webform_strtotime($element['#value']['month'] . '/' . $element['#value']['day'] . '/' . $element['#value']['year']);
$format = webform_date_format('medium');
$output = format_date($timestamp, 'custom', $format, 'UTC');
}
return $output;
}
/**
* Implements _webform_analysis_component().
*/
function _webform_analysis_date($component, $sids = array()) {
$query = db_select('webform_submitted_data', 'wsd', array('fetch' => PDO::FETCH_ASSOC))
->fields('wsd', array('no', 'data'))
->condition('nid', $component['nid'])
->condition('cid', $component['cid'])
->orderBy('sid');
if (count($sids)) {
$query->condition('sid', $sids, 'IN');
}
$result = $query->execute();
$dates = array();
$submissions = 0;
foreach ($result as $row) {
$submissions++;
if ($row['data']) {
$dates[] = webform_date_array($row['data']);
}
}
// Display stats.
$nonblanks = count($dates);
$rows[0] = array(t('Left Blank'), ($submissions - $nonblanks));
$rows[1] = array(t('User entered value'), $nonblanks);
return $rows;
}
/**
* Implements _webform_table_component().
*/
function _webform_table_date($component, $value) {
if ($value[0]) {
$timestamp = webform_strtotime($value[0]);
$format = webform_date_format('short');
return format_date($timestamp, 'custom', $format, 'UTC');
}
else {
return '';
}
}
/**
* Implements _webform_csv_headers_component().
*/
function _webform_csv_headers_date($component, $export_options) {
$header = array();
$header[0] = '';
$header[1] = '';
$header[2] = $component['name'];
return $header;
}
/**
* Implements _webform_csv_data_component().
*/
function _webform_csv_data_date($component, $export_options, $value) {
if ($value[0]) {
$timestamp = webform_strtotime($value[0]);
$format = webform_date_format('short');
return format_date($timestamp, 'custom', $format, 'UTC');
}
else {
return '';
}
}

View File

@@ -0,0 +1,285 @@
<?php
/**
* @file
* Webform module email component.
*/
/**
* Implements _webform_defaults_component().
*/
function _webform_defaults_email() {
return array(
'name' => '',
'form_key' => NULL,
'pid' => 0,
'weight' => 0,
'value' => '',
'mandatory' => 0,
'extra' => array(
'width' => '',
'unique' => 0,
'disabled' => 0,
'title_display' => 0,
'description' => '',
'attributes' => array(),
'private' => FALSE,
),
);
}
/**
* Implements _webform_theme_component().
*/
function _webform_theme_email() {
return array(
'webform_email' => array(
'render element' => 'element',
'file' => 'components/email.inc',
),
'webform_display_email' => array(
'render element' => 'element',
'file' => 'components/email.inc',
),
);
}
/**
* Implements _webform_edit_component().
*/
function _webform_edit_email($component) {
$form['value'] = array(
'#type' => 'textfield',
'#title' => t('Default value'),
'#default_value' => $component['value'],
'#description' => t('The default value of the field.') . theme('webform_token_help'),
'#size' => 60,
'#maxlength' => 127,
'#weight' => 0,
'#attributes' => ($component['value'] == '%useremail' && count(form_get_errors()) == 0) ? array('disabled' => TRUE) : array(),
'#id' => 'email-value',
);
$form['user_email'] = array(
'#type' => 'checkbox',
'#title' => t('User email as default'),
'#default_value' => $component['value'] == '%useremail' ? 1 : 0,
'#description' => t('Set the default value of this field to the user email, if he/she is logged in.'),
'#attributes' => array('onclick' => 'getElementById("email-value").value = (this.checked ? "%useremail" : ""); getElementById("email-value").disabled = this.checked;'),
'#weight' => 0,
'#element_validate' => array('_webform_edit_email_validate'),
);
$form['display']['width'] = array(
'#type' => 'textfield',
'#title' => t('Width'),
'#default_value' => $component['extra']['width'],
'#description' => t('Width of the textfield.') . ' ' . t('Leaving blank will use the default size.'),
'#size' => 5,
'#maxlength' => 10,
'#parents' => array('extra', 'width'),
);
$form['display']['disabled'] = array(
'#type' => 'checkbox',
'#title' => t('Disabled'),
'#return_value' => 1,
'#description' => t('Make this field non-editable. Useful for setting an unchangeable default value.'),
'#weight' => 11,
'#default_value' => $component['extra']['disabled'],
'#parents' => array('extra', 'disabled'),
);
$form['validation']['unique'] = array(
'#type' => 'checkbox',
'#title' => t('Unique'),
'#return_value' => 1,
'#description' => t('Check that all entered values for this field are unique. The same value is not allowed to be used twice.'),
'#weight' => 1,
'#default_value' => $component['extra']['unique'],
'#parents' => array('extra', 'unique'),
);
return $form;
}
/**
* Element validation function for the email edit form.
*/
function _webform_edit_email_validate($element, &$form_state) {
if ($form_state['values']['user_email']) {
$form_state['values']['value'] = '%useremail';
}
}
/**
* Implements _webform_render_component().
*/
function _webform_render_email($component, $value = NULL, $filter = TRUE) {
global $user;
$node = isset($component['nid']) ? node_load($component['nid']) : NULL;
$element = array(
'#type' => 'webform_email',
'#title' => $filter ? _webform_filter_xss($component['name']) : $component['name'],
'#title_display' => $component['extra']['title_display'] ? $component['extra']['title_display'] : 'before',
'#default_value' => $filter ? _webform_filter_values($component['value'], $node) : $component['value'],
'#required' => $component['mandatory'],
'#weight' => $component['weight'],
'#description' => $filter ? _webform_filter_descriptions($component['extra']['description'], $node) : $component['extra']['description'],
'#attributes' => $component['extra']['attributes'],
'#element_validate' => array('_webform_validate_email'),
'#theme_wrappers' => array('webform_element'),
'#translatable' => array('title', 'description'),
);
// Add an e-mail class for identifying the difference from normal textfields.
$element['#attributes']['class'][] = 'email';
// Enforce uniqueness.
if ($component['extra']['unique']) {
$element['#element_validate'][] = 'webform_validate_unique';
}
if (isset($value)) {
$element['#default_value'] = $value[0];
}
if ($component['extra']['disabled']) {
if ($filter) {
$element['#attributes']['readonly'] = 'readonly';
}
else {
$element['#disabled'] = TRUE;
}
}
// Change the 'width' option to the correct 'size' option.
if ($component['extra']['width'] > 0) {
$element['#size'] = $component['extra']['width'];
}
return $element;
}
/**
* Theme function to render an email component.
*/
function theme_webform_email($variables) {
$element = $variables['element'];
// This IF statement is mostly in place to allow our tests to set type="text"
// because SimpleTest does not support type="email".
if (!isset($element['#attributes']['type'])) {
$element['#attributes']['type'] = 'email';
}
// Convert properties to attributes on the element if set.
foreach (array('id', 'name', 'value', 'size') as $property) {
if (isset($element['#' . $property]) && $element['#' . $property] !== '') {
$element['#attributes'][$property] = $element['#' . $property];
}
}
_form_set_class($element, array('form-text', 'form-email'));
return '<input' . drupal_attributes($element['#attributes']) . ' />';
}
/**
* A Drupal Form API Validation function. Validates the entered values from
* email components on the client-side form.
*
* @param $form_element
* The e-mail form element.
* @param $form_state
* The full form state for the webform.
* @return
* None. Calls a form_set_error if the e-mail is not valid.
*/
function _webform_validate_email($form_element, &$form_state) {
$component = $form_element['#webform_component'];
$value = trim($form_element['#value']);
if ($value !== '' && !valid_email_address($value)) {
form_error($form_element, t('%value is not a valid email address.', array('%value' => $value)));
}
else {
form_set_value($form_element, $value, $form_state);
}
}
/**
* Implements _webform_display_component().
*/
function _webform_display_email($component, $value, $format = 'html') {
return array(
'#title' => $component['name'],
'#weight' => $component['weight'],
'#theme' => 'webform_display_email',
'#theme_wrappers' => $format == 'html' ? array('webform_element') : array('webform_element_text'),
'#format' => $format,
'#value' => isset($value[0]) ? $value[0] : '',
'#translatable' => array('title'),
);
}
/**
* Format the text output for this component.
*/
function theme_webform_display_email($variables) {
$element = $variables['element'];
$element['#value'] = empty($element['#value']) ? ' ' : $element['#value'];
return $element['#format'] == 'html' ? check_plain($element['#value']) : $element['#value'];
}
/**
* Implements _webform_analysis_component().
*/
function _webform_analysis_email($component, $sids = array()) {
$query = db_select('webform_submitted_data', 'wsd', array('fetch' => PDO::FETCH_ASSOC))
->fields('wsd', array('no', 'data'))
->condition('nid', $component['nid'])
->condition('cid', $component['cid']);
if (count($sids)) {
$query->condition('sid', $sids, 'IN');
}
$nonblanks = 0;
$submissions = 0;
$wordcount = 0;
$result = $query->execute();
foreach ($result as $data) {
if (drupal_strlen(trim($data['data'])) > 0) {
$nonblanks++;
$wordcount += str_word_count(trim($data['data']));
}
$submissions++;
}
$rows[0] = array(t('Left Blank'), ($submissions - $nonblanks));
$rows[1] = array(t('User entered value'), $nonblanks);
$rows[2] = array(t('Average submission length in words (ex blanks)'), ($nonblanks != 0 ? number_format($wordcount/$nonblanks, 2) : '0'));
return $rows;
}
/**
* Implements _webform_table_component().
*/
function _webform_table_email($component, $value) {
return check_plain(empty($value[0]) ? '' : $value[0]);
}
/**
* Implements _webform_csv_headers_component().
*/
function _webform_csv_headers_email($component, $export_options) {
$header = array();
$header[0] = '';
$header[1] = '';
$header[2] = $component['name'];
return $header;
}
/**
* Implements _webform_csv_data_component().
*/
function _webform_csv_data_email($component, $export_options, $value) {
return empty($value[0]) ? '' : $value[0];
}

View File

@@ -0,0 +1,100 @@
<?php
/**
* @file
* Webform module fieldset component.
*/
/**
* Implements _webform_defaults_component().
*/
function _webform_defaults_fieldset() {
return array(
'name' => '',
'form_key' => NULL,
'pid' => 0,
'weight' => 0,
'extra' => array(
'title_display' => 0,
'collapsible' => 0,
'collapsed' => 0,
'description' => '',
'private' => FALSE,
),
);
}
/**
* Implements _webform_edit_component().
*/
function _webform_edit_fieldset($component) {
$form = array();
$form['display']['collapsible'] = array(
'#type' => 'checkbox',
'#title' => t('Collapsible'),
'#default_value' => $component['extra']['collapsible'],
'#description' => t('If this fieldset is collapsible, the user may open or close the fieldset.'),
'#weight' => 0,
'#parents' => array('extra', 'collapsible'),
);
$form['display']['collapsed'] = array(
'#type' => 'checkbox',
'#title' => t('Collapsed by Default'),
'#default_value' => $component['extra']['collapsed'],
'#description' => t('Collapsible fieldsets are "open" by default. Select this option to default the fieldset to "closed."'),
'#weight' => 3,
'#parents' => array('extra', 'collapsed'),
);
return $form;
}
/**
* Implements _webform_render_component().
*/
function _webform_render_fieldset($component, $value = NULL, $filter = TRUE) {
$node = isset($component['nid']) ? node_load($component['nid']) : NULL;
$element = array(
'#type' => 'fieldset',
'#title' => $filter ? _webform_filter_xss($component['name']) : $component['name'],
'#title_display' => $component['extra']['title_display'] ? $component['extra']['title_display'] : NULL,
'#weight' => $component['weight'],
'#description' => $filter ? _webform_filter_descriptions($component['extra']['description'], $node) : $component['extra']['description'],
'#collapsible' => $component['extra']['collapsible'],
'#collapsed' => $component['extra']['collapsed'],
'#attributes' => array('class' => array('webform-component-fieldset'), 'id' => 'webform-component-' . $component['form_key']),
'#pre_render' => array('webform_fieldset_prerender', 'webform_element_title_display'),
'#translatable' => array('title', 'description'),
);
return $element;
}
/**
* Pre-render function to set a fieldset ID.
*/
function webform_fieldset_prerender($element) {
$element['#attributes']['id'] = 'webform-component-' . str_replace('_', '-', implode('--', array_slice($element['#parents'], 1)));
return $element;
}
/**
* Implements _webform_display_component().
*/
function _webform_display_fieldset($component, $value, $format = 'html') {
if ($format == 'text') {
$element = array(
'#title' => $component['name'],
'#weight' => $component['weight'],
'#theme_wrappers' => array('webform_element_text'),
'#translatable' => array('title'),
);
}
else {
$element = _webform_render_fieldset($component, $value);
}
$element['#format'] = $format;
return $element;
}

View File

@@ -0,0 +1,532 @@
<?php
/**
* @file
* Webform module file component.
*/
/**
* Implements _webform_defaults_component().
*/
function _webform_defaults_file() {
return array(
'name' => '',
'form_key' => NULL,
'mandatory' => 0,
'pid' => 0,
'weight' => 0,
'extra' => array(
'filtering' => array(
'types' => array('gif', 'jpg', 'png'),
'addextensions' => '',
'size' => '2 MB',
),
'scheme' => 'public',
'directory' => '',
'progress_indicator' => 'throbber',
'title_display' => 0,
'description' => '',
'attributes' => array(),
'private' => FALSE,
),
);
}
/**
* Implements _webform_theme_component().
*/
function _webform_theme_file() {
return array(
'webform_edit_file_extensions' => array(
'render element' => 'element',
'file' => 'components/file.inc',
),
'webform_display_file' => array(
'render element' => 'element',
'file' => 'components/file.inc',
),
);
}
/**
* Implements _webform_edit_component().
*/
function _webform_edit_file($component) {
$form = array();
$form['#element_validate'] = array('_webform_edit_file_check_directory');
$form['#after_build'] = array('_webform_edit_file_check_directory');
$form['validation']['size'] = array(
'#type' => 'textfield',
'#title' => t('Max upload size'),
'#default_value' => $component['extra']['filtering']['size'],
'#description' => t('Enter the max file size a user may upload such as 2 MB or 800 KB. Your server has a max upload size of @size.', array('@size' => format_size(file_upload_max_size()))),
'#size' => 10,
'#parents' => array('extra', 'filtering', 'size'),
'#element_validate' => array('_webform_edit_file_size_validate'),
'#weight' => 1,
);
$form['validation']['extensions'] = array(
'#element_validate' => array('_webform_edit_file_extensions_validate'),
'#parents' => array('extra', 'filtering'),
'#theme' => 'webform_edit_file_extensions',
'#theme_wrappers' => array('form_element'),
'#title' => t('Allowed file extensions'),
'#attached' => array(
'js' => array(drupal_get_path('module', 'webform') . '/js/webform-admin.js'),
'css' => array(drupal_get_path('module', 'webform') . '/css/webform-admin.css'),
),
'#weight' => 2,
);
// Find the list of all currently valid extensions.
$current_types = isset($component['extra']['filtering']['types']) ? $component['extra']['filtering']['types'] : array();
$types = array('gif', 'jpg', 'png');
$form['validation']['extensions']['types']['webimages'] = array(
'#type' => 'checkboxes',
'#title' => t('Web images'),
'#options' => drupal_map_assoc($types),
'#default_value' => array_intersect($current_types, $types),
);
$types = array('bmp', 'eps', 'tif', 'pict', 'psd');
$form['validation']['extensions']['types']['desktopimages'] = array(
'#type' => 'checkboxes',
'#title' => t('Desktop images'),
'#options' => drupal_map_assoc($types),
'#default_value' => array_intersect($current_types, $types),
);
$types = array('txt', 'rtf', 'html', 'odf', 'pdf', 'doc', 'docx', 'ppt', 'pptx', 'xls', 'xlsx', 'xml');
$form['validation']['extensions']['types']['documents'] = array(
'#type' => 'checkboxes',
'#title' => t('Documents'),
'#options' => drupal_map_assoc($types),
'#default_value' => array_intersect($current_types, $types),
);
$types = array('avi', 'mov', 'mp3', 'ogg', 'wav');
$form['validation']['extensions']['types']['media'] = array(
'#type' => 'checkboxes',
'#title' => t('Media'),
'#options' => drupal_map_assoc($types),
'#default_value' => array_intersect($current_types, $types),
);
$types = array('bz2', 'dmg', 'gz', 'jar', 'rar', 'sit', 'tar', 'zip');
$form['validation']['extensions']['types']['archives'] = array(
'#type' => 'checkboxes',
'#title' => t('Archives'),
'#options' => drupal_map_assoc($types),
'#default_value' => array_intersect($current_types, $types),
);
$form['validation']['extensions']['addextensions'] = array(
'#type' => 'textfield',
'#title' => t('Additional extensions'),
'#default_value' => $component['extra']['filtering']['addextensions'],
'#description' => t('Enter a list of additional file extensions for this upload field, separated by commas.<br /> Entered extensions will be appended to checked items above.'),
'#size' => 20,
'#weight' => 3,
);
$scheme_options = array();
foreach (file_get_stream_wrappers(STREAM_WRAPPERS_WRITE_VISIBLE) as $scheme => $stream_wrapper) {
$scheme_options[$scheme] = $stream_wrapper['name'];
}
$form['extra']['scheme'] = array(
'#type' => 'radios',
'#title' => t('Upload destination'),
'#options' => $scheme_options,
'#default_value' => $component['extra']['scheme'],
'#description' => t('Private file storage has significantly more overhead than public files, but restricts file access to users who can view submissions.'),
'#weight' => 4,
'#access' => count($scheme_options) > 1,
);
$form['extra']['directory'] = array(
'#type' => 'textfield',
'#title' => t('Upload directory'),
'#default_value' => $component['extra']['directory'],
'#description' => t('You may optionally specify a sub-directory to store your files.'),
'#weight' => 5,
'#field_prefix' => 'webform/',
);
$form['display']['progress_indicator'] = array(
'#type' => 'radios',
'#title' => t('Progress indicator'),
'#options' => array(
'throbber' => t('Throbber'),
'bar' => t('Bar with progress meter'),
),
'#default_value' => $component['extra']['progress_indicator'],
'#description' => t('The throbber display does not show the status of uploads but takes up less space. The progress bar is helpful for monitoring progress on large uploads.'),
'#weight' => 16,
'#access' => file_progress_implementation(),
'#parents' => array('extra', 'progress_indicator'),
);
// TODO: Make managed_file respect the "size" parameter.
/*
$form['display']['width'] = array(
'#type' => 'textfield',
'#title' => t('Width'),
'#default_value' => $component['extra']['width'],
'#description' => t('Width of the file field.') . ' ' . t('Leaving blank will use the default size.'),
'#size' => 5,
'#maxlength' => 10,
'#weight' => 4,
'#parents' => array('extra', 'width')
);
*/
return $form;
}
/**
* A Form API element validate function to check filesize is valid.
*/
function _webform_edit_file_size_validate($element) {
if (!empty($element['#value'])) {
$set_filesize = parse_size($element['#value']);
if ($set_filesize == FALSE) {
form_error($element, t('File size @value is not a valid filesize. Use a value such as 2 MB or 800 KB.', array('@value' => $element['#value'])));
}
else {
$max_filesize = parse_size(file_upload_max_size());
if ($max_filesize < $set_filesize) {
form_error($element, t('An upload size of @value is too large, you are allow to upload files @max or less.', array('@value' => $element['#value'], '@max' => format_size($max_filesize))));
}
}
}
}
/**
* A Form API after build and validate function.
*
* Ensure that the destination directory exists and is writable.
*/
function _webform_edit_file_check_directory($element) {
$scheme = $element['extra']['scheme']['#value'];
$directory = $element['extra']['directory']['#value'];
$destination_dir = file_stream_wrapper_uri_normalize($scheme . '://' . $directory . '/webform');
// Sanity check input to prevent use parent (../) directories.
if (preg_match('/\.\.[\/\\\]/', $destination_dir . '/')) {
form_error($element['extra']['directory'], t('The save directory %directory is not valid.', array('%directory' => $directory)));
}
else {
$destination_success = file_prepare_directory($destination_dir, FILE_CREATE_DIRECTORY);
if (!$destination_success) {
form_error($element['extra']['directory'], t('The save directory %directory could not be created. Check that the webform files directory is writable.', array('%directory' => $directory)));
}
}
return $element;
}
/**
* A Form API element validate function.
*
* Change the submitted values of the component so that all filtering extensions
* are saved as a single array.
*/
function _webform_edit_file_extensions_validate($element, &$form_state) {
// Predefined types.
$extensions = array();
foreach (element_children($element['types']) as $category) {
foreach (array_keys($element['types'][$category]['#value']) as $extension) {
if ($element['types'][$category][$extension]['#value']) {
$extensions[] = $extension;
}
}
}
// Additional types.
$additional_extensions = explode(',', $element['addextensions']['#value']);
foreach ($additional_extensions as $extension) {
$clean_extension = drupal_strtolower(trim($extension));
if (!empty($clean_extension) && !in_array($clean_extension, $extensions)) {
$extensions[] = $clean_extension;
}
}
form_set_value($element['types'], $extensions, $form_state);
}
/**
* Output the list of allowed extensions as checkboxes.
*/
function theme_webform_edit_file_extensions($variables) {
$element = $variables['element'];
// Format the components into a table.
$rows = array();
foreach (element_children($element['types']) as $filtergroup) {
$row = array();
$first_row = count($rows);
if ($element['types'][$filtergroup]['#type'] == 'checkboxes') {
$select_link = ' <a href="#" class="webform-select-link webform-select-link-' . $filtergroup . '">(' . t('select') . ')</a>';
$row[] = $element['types'][$filtergroup]['#title'];
$row[] = array('data' => $select_link, 'width' => 40);
$row[] = array('data' => drupal_render_children($element['types'][$filtergroup]), 'class' => array('webform-file-extensions', 'webform-select-group-' . $filtergroup));
$rows[] = array('data' => $row);
unset($element['types'][$filtergroup]);
}
}
// Add the row for additional types.
$row = array();
$title = $element['addextensions']['#title'];
$element['addextensions']['#title'] = NULL;
$row[] = array('data' => $title, 'colspan' => 2);
$row[] = drupal_render($element['addextensions']);
$rows[] = $row;
$header = array(array('data' => t('Category'), 'colspan' => '2'), array('data' => t('Types')));
// Create the table inside the form.
$element['types']['table'] = array(
'#theme' => 'table',
'#header' => $header,
'#rows' => $rows,
'#attributes' => array('class' => array('webform-file-extensions')),
);
return drupal_render_children($element);
}
/**
* Implements _webform_render_component().
*/
function _webform_render_file($component, $value = NULL, $filter = TRUE) {
$node = isset($component['nid']) ? node_load($component['nid']) : NULL;
// Cap the upload size according to the PHP limit.
$max_filesize = parse_size(file_upload_max_size());
$set_filesize = $component['extra']['filtering']['size'];
if (!empty($set_filesize) && parse_size($set_filesize) < $max_filesize) {
$max_filesize = parse_size($set_filesize);
}
$element = array(
'#type' => 'managed_file',
'#title' => $filter ? _webform_filter_xss($component['name']) : $component['name'],
'#title_display' => $component['extra']['title_display'] ? $component['extra']['title_display'] : 'before',
'#required' => $component['mandatory'],
'#default_value' => isset($value[0]) ? $value[0] : NULL,
'#attributes' => $component['extra']['attributes'],
'#upload_validators' => array(
'file_validate_size' => array($max_filesize),
'file_validate_extensions' => array(implode(' ', $component['extra']['filtering']['types'])),
),
'#pre_render' => array_merge(element_info_property('managed_file', '#pre_render'), array('webform_file_allow_access')),
'#upload_location' => $component['extra']['scheme'] . '://webform/' . $component['extra']['directory'],
'#progress_indicator' => $component['extra']['progress_indicator'],
'#description' => $filter ? _webform_filter_descriptions($component['extra']['description'], $node) : $component['extra']['description'],
'#weight' => $component['weight'],
'#theme_wrappers' => array('webform_element'),
'#translatable' => array('title', 'description'),
);
return $element;
}
/**
* Implements _webform_submit_component().
*/
function _webform_submit_file($component, $value) {
if (is_array($value)) {
return !empty($value['fid']) ? $value['fid'] : '';
}
else {
return !empty($value) ? $value : '';
}
}
/**
* Pre-render callback to allow access to uploaded files.
*
* Files that have not yet been saved into a submission must be accessible to
* the user who uploaded it, but no one else. After the submission is saved,
* access is granted through the file_usage table. Before then, we use a
* $_SESSION value to record a user's upload.
*
* @see webform_file_download()
*/
function webform_file_allow_access($element) {
if (!empty($element['#value']['fid'])) {
$fid = $element['#value']['fid'];
$_SESSION['webform_files'][$fid] = $fid;
}
return $element;
}
/**
* Implements _webform_display_component().
*/
function _webform_display_file($component, $value, $format = 'html') {
$fid = isset($value[0]) ? $value[0] : NULL;
return array(
'#title' => $component['name'],
'#value' => $fid ? webform_get_file($fid) : NULL,
'#weight' => $component['weight'],
'#theme' => 'webform_display_file',
'#theme_wrappers' => $format == 'text' ? array('webform_element_text') : array('webform_element'),
'#format' => $format,
'#translatable' => array('title'),
);
}
/**
* Format the output of text data for this component
*/
function theme_webform_display_file($variables) {
$element = $variables['element'];
$file = $element['#value'];
$url = !empty($file) ? webform_file_url($file->uri) : t('no upload');
return !empty($file) ? ($element['#format'] == 'text' ? $url : l($file->filename, $url)) : ' ';
}
/**
* Implements _webform_delete_component().
*/
function _webform_delete_file($component, $value) {
// Delete an individual submission file.
if (!empty($value[0]) && ($file = webform_get_file($value[0]))) {
file_usage_delete($file, 'webform');
file_delete($file);
}
}
/**
* Implements _webform_attachments_component().
*/
function _webform_attachments_file($component, $value) {
$file = (array) webform_get_file($value[0]);
//This is necessary until the next release of mimemail is out, see [#1388786]
$file['filepath'] = $file['uri'];
$files = array($file);
return $files;
}
/**
* Implements _webform_analysis_component().
*/
function _webform_analysis_file($component, $sids = array()) {
$query = db_select('webform_submitted_data', 'wsd', array('fetch' => PDO::FETCH_ASSOC))
->fields('wsd', array('no', 'data'))
->condition('nid', $component['nid'])
->condition('cid', $component['cid']);
if (count($sids)) {
$query->condition('sid', $sids, 'IN');
}
$nonblanks = 0;
$sizetotal = 0;
$submissions = 0;
$result = $query->execute();
foreach ($result as $data) {
$file = webform_get_file($data['data']);
if (isset($file->filesize)) {
$nonblanks++;
$sizetotal += $file->filesize;
}
$submissions++;
}
$rows[0] = array(t('Left Blank'), ($submissions - $nonblanks));
$rows[1] = array(t('User uploaded file'), $nonblanks);
$rows[2] = array(t('Average uploaded file size'), ($sizetotal != 0 ? (int) (($sizetotal/$nonblanks)/1024) . ' KB' : '0'));
return $rows;
}
/**
* Implements _webform_table_component().
*/
function _webform_table_file($component, $value) {
$output = '';
$file = webform_get_file($value[0]);
if (!empty($file->fid)) {
$output = '<a href="' . webform_file_url($file->uri) . '">' . check_plain(webform_file_name($file->uri)) . '</a>';
$output .= ' (' . (int) ($file->filesize/1024) . ' KB)';
}
return $output;
}
/**
* Implements _webform_csv_headers_component().
*/
function _webform_csv_headers_file($component, $export_options) {
$header = array();
// Two columns in header.
$header[0] = array('', '');
$header[1] = array($component['name'], '');
$header[2] = array(t('Name'), t('Filesize (KB)'));
return $header;
}
/**
* Implements _webform_csv_data_component().
*/
function _webform_csv_data_file($component, $export_options, $value) {
$file = webform_get_file($value[0]);
return empty($file->filename) ? array('', '') : array(webform_file_url($file->uri), (int) ($file->filesize/1024));
}
/**
* Helper function to create proper file names for uploaded file.
*/
function webform_file_name($filepath) {
if (!empty($filepath)) {
$info = pathinfo($filepath);
$file_name = $info['basename'];
}
return isset($file_name) ? $file_name : '';
}
/**
* Helper function to create proper URLs for uploaded file.
*/
function webform_file_url($uri) {
if (!empty($uri)) {
$file_url = file_create_url($uri);
}
return isset($file_url) ? $file_url : '';
}
/**
* Helper function to load a file from the database.
*/
function webform_get_file($fid) {
// Simple check to prevent loading of NULL values, which throws an entity
// system error.
return $fid ? file_load($fid) : FALSE;
}
/**
* Given a submission with file_usage set, add or remove file usage entries.
*/
function webform_file_usage_adjust($submission) {
if (isset($submission->file_usage)) {
$files = file_load_multiple($submission->file_usage['added_fids']);
foreach ($files as $file) {
$file->status = 1;
file_save($file);
file_usage_add($file, 'webform', 'submission', $submission->sid);
}
$files = file_load_multiple($submission->file_usage['deleted_fids']);
foreach ($files as $file) {
file_usage_delete($file, 'webform', 'submission', $submission->sid);
file_delete($file);
}
}
}

View File

@@ -0,0 +1,430 @@
<?php
/**
* @file
* Webform module grid component.
*/
// Grid depends on functions provided by select.
webform_component_include('select');
/**
* Implements _webform_defaults_component().
*/
function _webform_defaults_grid() {
return array(
'name' => '',
'form_key' => NULL,
'mandatory' => 0,
'pid' => 0,
'weight' => 0,
'extra' => array(
'options' => '',
'questions' => '',
'optrand' => 0,
'qrand' => 0,
'title_display' => 0,
'custom_option_keys' => 0,
'custom_question_keys' => 0,
'description' => '',
'private' => FALSE,
),
);
}
/**
* Implements _webform_theme_component().
*/
function _webform_theme_grid() {
return array(
'webform_grid' => array(
'render element' => 'element',
'file' => 'components/grid.inc',
),
'webform_display_grid' => array(
'render element' => 'element',
'file' => 'components/grid.inc',
),
);
}
/**
* Implements _webform_edit_component().
*/
function _webform_edit_grid($component) {
$form = array();
if (module_exists('options_element')) {
$form['options'] = array(
'#type' => 'fieldset',
'#title' => t('Options'),
'#collapsible' => TRUE,
'#description' => t('Options to select across the top. Usually these are ratings such as "poor" through "excellent" or "strongly disagree" through "strongly agree".'),
'#attributes' => array('class' => array('webform-options-element')),
'#element_validate' => array('_webform_edit_validate_options'),
);
$form['options']['options'] = array(
'#type' => 'options',
'#options' => _webform_select_options_from_text($component['extra']['options'], TRUE),
'#optgroups' => FALSE,
'#default_value' => FALSE,
'#default_value_allowed' => FALSE,
'#optgroups' => FALSE,
'#key_type' => 'mixed',
'#key_type_toggle' => t('Customize option keys (Advanced)'),
'#key_type_toggled' => $component['extra']['custom_option_keys'],
);
$form['questions'] = array(
'#type' => 'fieldset',
'#title' => t('Questions'),
'#collapsible' => TRUE,
'#description' => t('Questions list down the side of the grid.'),
'#attributes' => array('class' => array('webform-options-element')),
'#element_validate' => array('_webform_edit_validate_options'),
);
$form['questions']['options'] = array(
'#type' => 'options',
'#options' => _webform_select_options_from_text($component['extra']['questions'], TRUE),
'#optgroups' => FALSE,
'#default_value' => FALSE,
'#default_value_allowed' => FALSE,
'#optgroups' => FALSE,
'#key_type' => 'mixed',
'#key_type_toggle' => t('Customize question keys (Advanced)'),
'#key_type_toggled' => $component['extra']['custom_question_keys'],
);
}
else {
$form['extra']['options'] = array(
'#type' => 'textarea',
'#title' => t('Options'),
'#default_value' => $component['extra']['options'],
'#description' => t('Options to select across the top. One option per line. <strong>Key-value pairs MUST be specified as "safe_key|Some readable option"</strong>. Use of only alphanumeric characters and underscores is recommended in keys.') . theme('webform_token_help'),
'#cols' => 60,
'#rows' => 5,
'#weight' => -3,
'#required' => TRUE,
'#wysiwyg' => FALSE,
'#element_validate' => array('_webform_edit_validate_select'),
);
$form['extra']['questions'] = array(
'#type' => 'textarea',
'#title' => t('Questions'),
'#default_value' => $component['extra']['questions'],
'#description' => t('Questions list down the side of the grid. One question per line. <strong>Key-value pairs MUST be specified as "safe_key|Some readable option"</strong>. Use of only alphanumeric characters and underscores is recommended in keys.') . theme('webform_token_help'),
'#cols' => 60,
'#rows' => 5,
'#weight' => -2,
'#required' => TRUE,
'#wysiwyg' => FALSE,
'#element_validate' => array('_webform_edit_validate_select'),
);
}
$form['display']['optrand'] = array(
'#type' => 'checkbox',
'#title' => t('Randomize Options'),
'#default_value' => $component['extra']['optrand'],
'#description' => t('Randomizes the order of options on the top when they are displayed in the form.'),
'#parents' => array('extra', 'optrand')
);
$form['display']['qrand'] = array(
'#type' => 'checkbox',
'#title' => t('Randomize Questions'),
'#default_value' => $component['extra']['qrand'],
'#description' => t('Randomize the order of the questions on the side when they are displayed in the form.'),
'#parents' => array('extra', 'qrand')
);
return $form;
}
/**
* Implements _webform_render_component().
*/
function _webform_render_grid($component, $value = NULL, $filter = TRUE) {
$node = isset($component['nid']) ? node_load($component['nid']) : NULL;
$element = array(
'#type' => 'webform_grid',
'#title' => $filter ? _webform_filter_xss($component['name']) : $component['name'],
'#title_display' => $component['extra']['title_display'] ? $component['extra']['title_display'] : 'before',
'#required' => $component['mandatory'],
'#weight' => $component['weight'],
'#description' => $filter ? _webform_filter_descriptions($component['extra']['description'], $node) : $component['extra']['description'],
'#grid_questions' => _webform_select_options_from_text($component['extra']['questions'], TRUE),
'#grid_options' => _webform_select_options_from_text($component['extra']['options'], TRUE),
'#optrand' => $component['extra']['optrand'],
'#qrand' => $component['extra']['qrand'],
'#theme' => 'webform_grid',
'#theme_wrappers' => array('webform_element'),
'#process' => array('webform_expand_grid'),
'#translatable' => array('title', 'description', 'grid_options', 'grid_questions'),
);
if ($value) {
$element['#default_value'] = $value;
}
return $element;
}
/**
* A Form API #process function for Webform grid fields.
*/
function webform_expand_grid($element) {
$options = $element['#grid_options'];
$questions = $element['#grid_questions'];
if (!empty($element['#optrand'])) {
_webform_shuffle_options($options);
}
if (!empty($element['#qrand'])) {
_webform_shuffle_options($questions);
}
foreach ($questions as $key => $question) {
if ($question != '') {
$element[$key] = array(
'#title' => $question,
'#required' => $element['#required'],
'#options' => $options,
'#type' => 'radios',
'#process' => array('form_process_radios', 'webform_expand_select_ids'),
// Webform handles validation manually.
'#validated' => TRUE,
'#webform_validated' => FALSE,
'#translatable' => array('title'),
);
}
}
$value = isset($element['#default_value']) ? $element['#default_value'] : array();
foreach (element_children($element) as $key) {
if (isset($value[$key])) {
$element[$key]['#default_value'] = ($value[$key] !== '') ? $value[$key] : NULL;
}
else {
$element[$key]['#default_value'] = NULL;
}
}
return $element;
}
/**
* Implements _webform_display_component().
*/
function _webform_display_grid($component, $value, $format = 'html') {
$questions = _webform_select_options_from_text($component['extra']['questions'], TRUE);
$options = _webform_select_options_from_text($component['extra']['options'], TRUE);
$element = array(
'#title' => $component['name'],
'#weight' => $component['weight'],
'#format' => $format,
'#grid_questions' => $questions,
'#grid_options' => $options,
'#theme' => 'webform_display_grid',
'#theme_wrappers' => $format == 'html' ? array('webform_element') : array('webform_element_text'),
'#sorted' => TRUE,
'#translatable' => array('#title', '#grid_questions', '#grid_options'),
);
foreach ($questions as $key => $question) {
if ($question !== '') {
$element[$key] = array(
'#title' => $question,
'#value' => isset($value[$key]) ? $value[$key] : NULL,
'#translatable' => array('#title', '#value'),
);
}
}
return $element;
}
/**
* Format the text output for this component.
*/
function theme_webform_display_grid($variables) {
$element = $variables['element'];
$component = $element['#webform_component'];
$format = $element['#format'];
if ($format == 'html') {
$rows = array();
$header = array(array('data' => '', 'class' => array('webform-grid-question')));
foreach ($element['#grid_options'] as $option) {
$header[] = array('data' => _webform_filter_xss($option), 'class' => array('checkbox', 'webform-grid-option'));
}
foreach ($element['#grid_questions'] as $question_key => $question) {
$row = array();
$row[] = array('data' => _webform_filter_xss($question), 'class' => array('webform-grid-question'));
foreach ($element['#grid_options'] as $option_value => $option_label) {
if (strcmp($element[$question_key]['#value'], $option_value) == 0) {
$row[] = array('data' => '<strong>X</strong>', 'class' => array('checkbox', 'webform-grid-option'));
}
else {
$row[] = array('data' => '&nbsp;', 'class' => array('checkbox', 'webform-grid-option'));
}
}
$rows[] = $row;
}
$option_count = count($header) - 1;
$output = theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => array('class' => array('webform-grid', 'webform-grid-' . $option_count))));
}
else {
$items = array();
foreach (element_children($element) as $key) {
$items[] = ' - ' . $element[$key]['#title'] . ': ' . (isset($element['#grid_options'][$element[$key]['#value']]) ? $element['#grid_options'][$element[$key]['#value']] : '');
}
$output = implode("\n", $items);
}
return $output;
}
/**
* Implements _webform_analysis_component().
*/
function _webform_analysis_grid($component, $sids = array()) {
// Generate the list of options and questions.
$options = _webform_select_options_from_text($component['extra']['options'], TRUE);
$questions = _webform_select_options_from_text($component['extra']['questions'], TRUE);
// Generate a lookup table of results.
$query = db_select('webform_submitted_data', 'wsd')
->fields('wsd', array('no', 'data'))
->condition('nid', $component['nid'])
->condition('cid', $component['cid'])
->condition('data', '', '<>')
->groupBy('no')
->groupBy('data');
$query->addExpression('COUNT(sid)', 'datacount');
if (count($sids)) {
$query->condition('sid', $sids, 'IN');
}
$result = $query->execute();
$counts = array();
foreach ($result as $data) {
$counts[$data->no][$data->data] = $data->datacount;
}
// Create an entire table to be put into the returned row.
$rows = array();
$header = array('');
// Add options as a header row.
foreach ($options as $option) {
$header[] = _webform_filter_xss($option);
}
// Add questions as each row.
foreach ($questions as $qkey => $question) {
$row = array(_webform_filter_xss($question));
foreach ($options as $okey => $option) {
$row[] = !empty($counts[$qkey][$okey]) ? $counts[$qkey][$okey] : 0;
}
$rows[] = $row;
}
$output = theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => array('class' => array('webform-grid'))));
return array(array(array('data' => $output, 'colspan' => 2)));
}
/**
* Implements _webform_table_component().
*/
function _webform_table_grid($component, $value) {
$questions = _webform_select_options_from_text($component['extra']['questions'], TRUE);
$options = _webform_select_options_from_text($component['extra']['options'], TRUE);
$output = '';
// Set the value as a single string.
foreach ($questions as $key => $label) {
if (isset($value[$key]) && isset($options[$value[$key]])) {
$output .= _webform_filter_xss($label) . ': ' . _webform_filter_xss($options[$value[$key]]) . '<br />';
}
}
return $output;
}
/**
* Implements _webform_csv_headers_component().
*/
function _webform_csv_headers_grid($component, $export_options) {
$header = array();
$header[0] = array('');
$header[1] = array($component['name']);
$items = _webform_select_options_from_text($component['extra']['questions'], TRUE);
$count = 0;
foreach ($items as $key => $item) {
// Empty column per sub-field in main header.
if ($count != 0) {
$header[0][] = '';
$header[1][] = '';
}
// The value for this option.
$header[2][] = $item;
$count++;
}
return $header;
}
/**
* Implements _webform_csv_data_component().
*/
function _webform_csv_data_grid($component, $export_options, $value) {
$questions = _webform_select_options_from_text($component['extra']['questions'], TRUE);
$options = _webform_select_options_from_text($component['extra']['options'], TRUE);
$return = array();
foreach ($questions as $key => $question) {
if (isset($value[$key]) && isset($options[$value[$key]])) {
$return[] = $export_options['select_keys'] ? $value[$key] : $options[$value[$key]];
}
else {
$return[] = '';
}
}
return $return;
}
function theme_webform_grid($variables) {
$element = $variables['element'];
$rows = array();
$header = array(array('data' => '', 'class' => array('webform-grid-question')));
// Set the header for the table.
foreach ($element['#grid_options'] as $option) {
$header[] = array('data' => _webform_filter_xss($option), 'class' => array('checkbox', 'webform-grid-option'));
}
foreach (element_children($element) as $key) {
$question_element = $element[$key];
// Create a row with the question title.
$row = array(array('data' => _webform_filter_xss($question_element['#title']), 'class' => array('webform-grid-question')));
// Render each radio button in the row.
$radios = form_process_radios($question_element);
foreach (element_children($radios) as $key) {
$radios[$key]['#title_display'] = 'invisible';
$row[] = array('data' => drupal_render($radios[$key]), 'class' => array('checkbox', 'webform-grid-option'));
}
$rows[] = $row;
}
$option_count = count($header) - 1;
return theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => array('class' => array('webform-grid', 'webform-grid-' . $option_count))));
}

View File

@@ -0,0 +1,179 @@
<?php
/**
* @file
* Webform module hidden component.
*/
/**
* Implements _webform_defaults_component().
*/
function _webform_defaults_hidden() {
return array(
'name' => '',
'form_key' => NULL,
'pid' => 0,
'weight' => 0,
'value' => '',
'extra' => array(
'private' => FALSE,
'hidden_type' => 'value',
),
);
}
/**
* Implements _webform_theme_component().
*/
function _webform_theme_hidden() {
return array(
'webform_display_hidden' => array(
'render element' => 'element',
'file' => 'components/hidden.inc',
),
);
}
/**
* Implements _webform_edit_component().
*/
function _webform_edit_hidden($component) {
$form = array();
$form['value'] = array(
'#type' => 'textarea',
'#title' => t('Default value'),
'#default_value' => $component['value'],
'#description' => t('The default value of the field.') . theme('webform_token_help'),
'#cols' => 60,
'#rows' => 5,
'#weight' => 0,
);
$form['display']['hidden_type'] = array(
'#type' => 'radios',
'#options' => array(
'value' => t('Secure value (allows use of all tokens)'),
'hidden' => t('Hidden element (less secure, changeable via JavaScript)'),
),
'#title' => t('Hidden type'),
'#description' => t('Both types of hidden fields are not shown to end-users. Using a <em>Secure value</em> allows the use of <em>all tokens</em>, even for anonymous users.'),
'#default_value' => $component['extra']['hidden_type'],
'#parents' => array('extra', 'hidden_type'),
);
return $form;
}
/**
* Implements _webform_render_component().
*/
function _webform_render_hidden($component, $value = NULL, $filter = TRUE) {
$node = isset($component['nid']) ? node_load($component['nid']) : NULL;
// Set filtering options for "value" types, which are not displayed to the
// end user so they do not need to be sanitized.
$strict = $component['extra']['hidden_type'] != 'value';
$allow_anonymous = $component['extra']['hidden_type'] == 'value';
$default_value = $filter ? _webform_filter_values($component['value'], $node, NULL, NULL, $strict, $allow_anonymous) : $component['value'];
if (isset($value[0])) {
$default_value = $value[0];
}
$element = array(
'#title' => $filter ? _webform_filter_xss($component['name']) : $component['name'],
'#weight' => $component['weight'],
'#translatable' => array('title'),
);
if ($component['extra']['hidden_type'] == 'value') {
$element['#type'] = 'value';
$element['#value'] = $default_value;
}
else {
$element['#type'] = 'hidden';
$element['#default_value'] = $default_value;
}
return $element;
}
/**
* Implements _webform_display_component().
*/
function _webform_display_hidden($component, $value, $format = 'html') {
$element = array(
'#title' => $component['name'],
'#markup' => isset($value[0]) ? $value[0] : NULL,
'#weight' => $component['weight'],
'#format' => $format,
'#theme' => 'webform_display_hidden',
'#theme_wrappers' => $format == 'text' ? array('webform_element_text') : array('webform_element'),
'#translatable' => array('title'),
);
return $element;
}
function theme_webform_display_hidden($variables) {
$element = $variables['element'];
return $element['#format'] == 'html' ? check_plain($element['#markup']) : $element['#markup'];
}
/**
* Implements _webform_analysis_component().
*/
function _webform_analysis_hidden($component, $sids = array()) {
$query = db_select('webform_submitted_data', 'wsd', array('fetch' => PDO::FETCH_ASSOC))
->fields('wsd', array('no', 'data'))
->condition('nid', $component['nid'])
->condition('cid', $component['cid']);
if (count($sids)) {
$query->condition('sid', $sids, 'IN');
}
$nonblanks = 0;
$submissions = 0;
$wordcount = 0;
$result = $query->execute();
foreach ($result as $data) {
if (strlen(trim($data['data'])) > 0) {
$nonblanks++;
$wordcount += str_word_count(trim($data['data']));
}
$submissions++;
}
$rows[0] = array( t('Empty'), ($submissions - $nonblanks));
$rows[1] = array( t('Non-empty'), $nonblanks);
$rows[2] = array( t('Average submission length in words (ex blanks)'),
($nonblanks !=0 ? number_format($wordcount/$nonblanks, 2) : '0'));
return $rows;
}
/**
* Implements _webform_csv_data_component().
*/
function _webform_table_hidden($component, $value) {
return check_plain(empty($value[0]) ? '' : $value[0]);
}
/**
* Implements _webform_csv_data_component().
*/
function _webform_csv_headers_hidden($component, $export_options) {
$header = array();
$header[0] = '';
$header[1] = '';
$header[2] = $component['name'];
return $header;
}
/**
* Implements _webform_csv_data_component().
*/
function _webform_csv_data_hidden($component, $export_options, $value) {
return isset($value[0]) ? $value[0] : '';
}

View File

@@ -0,0 +1,80 @@
<?php
/**
* @file
* Webform module markup component.
*/
/**
* Implements _webform_defaults_component().
*/
function _webform_defaults_markup() {
return array(
'name' => '',
'form_key' => NULL,
'pid' => 0,
'weight' => 0,
'value' => '',
'extra' => array(
'format' => NULL,
'private' => FALSE,
),
);
}
/**
* Implements _webform_edit_component().
*/
function _webform_edit_markup($component) {
$form = array();
$form['value'] = array(
'#type' => 'text_format',
'#title' => t('Value'),
'#default_value' => $component['value'],
'#description' => t('Markup allows you to enter custom HTML or PHP logic into your form.') . theme('webform_token_help'),
'#weight' => -1,
'#format' => $component['extra']['format'],
'#element_validate' => array('_webform_edit_markup_validate'),
);
return $form;
}
/**
* Element validate handler; Set the text format value.
*/
function _webform_edit_markup_validate($form, &$form_state) {
if (is_array($form_state['values']['value'])) {
$form_state['values']['extra']['format'] = $form_state['values']['value']['format'];
$form_state['values']['value'] = $form_state['values']['value']['value'];
}
}
/**
* Implements _webform_render_component().
*/
function _webform_render_markup($component, $value = NULL, $filter = TRUE) {
$node = isset($component['nid']) ? node_load($component['nid']) : NULL;
$element = array(
'#type' => 'markup',
'#title' => $filter ? NULL : $component['name'],
'#weight' => $component['weight'],
'#markup' => $filter ? _webform_filter_values(check_markup($component['value'], $component['extra']['format'], '', TRUE), $node, NULL, NULL, FALSE) : $component['value'],
'#format' => $component['extra']['format'],
'#theme_wrappers' => array('webform_element'),
'#translatable' => array('title', 'markup'),
);
// TODO: Remove when #markup becomes available in D7.
$element['#value'] = $element['#markup'];
return $element;
}
/**
* Implements _webform_display_component().
*/
function _webform_display_markup($component, $value, $format = 'html') {
return array();
}

View File

@@ -0,0 +1,721 @@
<?php
/**
* @file
* Webform module number component.
*/
/**
* Implements _webform_defaults_component().
*/
function _webform_defaults_number() {
return array(
'name' => '',
'form_key' => NULL,
'pid' => 0,
'weight' => 0,
'value' => '',
'mandatory' => 0,
'extra' => array(
'type' => 'textfield',
'field_prefix' => '',
'field_suffix' => '',
'unique' => 0,
'title_display' => 0,
'description' => '',
'attributes' => array(),
'private' => FALSE,
'min' => '',
'max' => '',
'step' => '',
'decimals' => '',
'point' => '.',
'separator' => ',',
'integer' => 0,
'excludezero' => 0,
),
);
}
/**
* Implements _webform_theme_component().
*/
function _webform_theme_number() {
return array(
'webform_number' => array(
'render element' => 'element',
'file' => 'components/number.inc',
),
'webform_display_number' => array(
'render element' => 'element',
'file' => 'components/number.inc',
),
);
}
/**
* Implements _webform_edit_component().
*/
function _webform_edit_number($component) {
$form = array();
$form['value'] = array(
'#type' => 'textfield',
'#title' => t('Default value'),
'#default_value' => $component['value'],
'#description' => t('The default value of the field.') . theme('webform_token_help'),
'#size' => 60,
'#maxlength' => 1024,
'#weight' => 0,
);
$form['display']['type'] = array(
'#type' => 'radios',
'#title' => t('Element type'),
'#options' => array(
'textfield' => t('Text field'),
'select' => t('Select list'),
),
'#default_value' => $component['extra']['type'],
'#description' => t('A minimum and maximum value are required if displaying as a select.'),
'#weight' => -1,
'#parents' => array('extra', 'type'),
);
$form['display']['field_prefix'] = array(
'#type' => 'textfield',
'#title' => t('Prefix text placed to the left of the field'),
'#default_value' => $component['extra']['field_prefix'],
'#description' => t('Examples: $, #, -.'),
'#size' => 20,
'#maxlength' => 127,
'#weight' => 1.1,
'#parents' => array('extra', 'field_prefix'),
);
$form['display']['field_suffix'] = array(
'#type' => 'textfield',
'#title' => t('Postfix text placed to the right of the field'),
'#default_value' => $component['extra']['field_suffix'],
'#description' => t('Examples: lb, kg, %.'),
'#size' => 20,
'#maxlength' => 127,
'#weight' => 1.2,
'#parents' => array('extra', 'field_suffix'),
);
$form['display']['decimals'] = array(
'#type' => 'select',
'#title' => t('Decimal places'),
'#options' => array('' => t('Automatic')) + drupal_map_assoc(range(0, 10)),
'#description' => t('Automatic will display up to @count decimals places if needed. A value of "2" is common to format currency amounts.', array('@count' => '4')),
'#default_value' => $component['extra']['decimals'],
'#weight' => 2,
'#parents' => array('extra', 'decimals'),
'#element_validate' => array('_webform_edit_number_validate'),
);
$form['display']['separator'] = array(
'#type' => 'select',
'#title' => t('Thousands separator'),
'#options' => array(
',' => t('Comma (,)'),
'.' => t('Period (.)'),
' ' => t('Space ( )'),
'' => t('None'),
),
'#default_value' => $component['extra']['separator'],
'#weight' => 3,
'#parents' => array('extra', 'separator'),
'#element_validate' => array('_webform_edit_number_validate'),
);
$form['display']['point'] = array(
'#type' => 'select',
'#title' => t('Decimal point'),
'#options' => array(
',' => t('Comma (,)'),
'.' => t('Period (.)'),
),
'#default_value' => $component['extra']['point'],
'#weight' => 4,
'#parents' => array('extra', 'point'),
'#element_validate' => array('_webform_edit_number_validate'),
);
$form['validation']['unique'] = array(
'#type' => 'checkbox',
'#title' => t('Unique'),
'#return_value' => 1,
'#description' => t('Check that all entered values for this field are unique. The same value is not allowed to be used twice.'),
'#weight' => 1,
'#default_value' => $component['extra']['unique'],
'#parents' => array('extra', 'unique'),
);
$form['validation']['integer'] = array(
'#type' => 'checkbox',
'#title' => t('Integer'),
'#return_value' => 1,
'#description' => t('Permit only integer values as input. e.g. 12.34 would be invalid.'),
'#weight' => 1.5,
'#default_value' => $component['extra']['integer'],
'#parents' => array('extra', 'integer'),
);
$form['validation']['min'] = array(
'#type' => 'textfield',
'#title' => t('Minimum'),
'#default_value' => $component['extra']['min'],
'#description' => t('Minimum numeric value. e.g. 0 would ensure positive numbers.'),
'#size' => 5,
'#maxlength' => 10,
'#weight' => 2.1,
'#parents' => array('extra', 'min'),
'#element_validate' => array('_webform_edit_number_validate'),
);
$form['validation']['max'] = array(
'#type' => 'textfield',
'#title' => t('Maximum'),
'#default_value' => $component['extra']['max'],
'#description' => t('Maximum numeric value. This may also determine the display width of your field.'),
'#size' => 5,
'#maxlength' => 10,
'#weight' => 2.2,
'#parents' => array('extra', 'max'),
'#element_validate' => array('_webform_edit_number_validate'),
);
$form['validation']['step'] = array(
'#type' => 'textfield',
'#title' => t('Step'),
'#default_value' => $component['extra']['step'],
'#description' => t('Limit options to a specific increment. e.g. a step of "5" would allow values 5, 10, 15, etc.'),
'#size' => 5,
'#maxlength' => 10,
'#weight' => 3,
'#parents' => array('extra', 'step'),
'#element_validate' => array('_webform_edit_number_validate'),
);
// Analysis settings.
$form['analysis'] = array(
'#type' => 'fieldset',
'#title' => t('Analysis'),
'#collapsible' => TRUE,
'#collapsed' => FALSE,
'#weight' => 10,
);
$form['analysis']['excludezero'] = array(
'#type' => 'checkbox',
'#title' => t('Exclude zero'),
'#return_value' => 1,
'#description' => t('Exclude entries of zero (or blank) when counting submissions to calculate average and standard deviation.'),
'#weight' => 1.5,
'#default_value' => $component['extra']['excludezero'],
'#parents' => array('extra', 'excludezero'),
);
return $form;
}
/**
* Theme function to render a number component.
*/
function theme_webform_number($variables) {
$element = $variables['element'];
// This IF statement is mostly in place to allow our tests to set type="text"
// because SimpleTest does not support type="number".
if (!isset($element['#attributes']['type'])) {
$element['#attributes']['type'] = 'number';
}
// Step property *must* be a full number with 0 prefix if a decimal.
if (!empty($element['#step']) && !is_int($element['#step'] * 1)) {
$decimals = strlen($element['#step']) - strrpos($element['#step'], '.') - 1;
$element['#step'] = sprintf('%1.' . $decimals . 'F', $element['#step']);
}
// If the number is not an integer and step is undefined/empty, set the "any"
// value to allow any decimal.
if (empty($element['#integer']) && empty($element['#step'])) {
$element['#step'] = 'any';
}
elseif ($element['#integer'] && empty($element['#step'])) {
$element['#step'] = 1;
}
// Convert properties to attributes on the element if set.
foreach (array('id', 'name', 'value', 'size', 'min', 'max', 'step') as $property) {
if (isset($element['#' . $property]) && $element['#' . $property] !== '') {
$element['#attributes'][$property] = $element['#' . $property];
}
}
_form_set_class($element, array('form-text', 'form-number'));
return '<input' . drupal_attributes($element['#attributes']) . ' />';
}
/**
* Implements _webform_render_component().
*/
function _webform_render_number($component, $value = NULL, $filter = TRUE) {
$node = isset($component['nid']) ? node_load($component['nid']) : NULL;
$element = array(
'#title' => $filter ? _webform_filter_xss($component['name']) : $component['name'],
'#title_display' => $component['extra']['title_display'] ? $component['extra']['title_display'] : 'before',
'#default_value' => $filter ? _webform_filter_values($component['value'], $node, NULL, NULL, FALSE) : $component['value'],
'#required' => $component['mandatory'],
'#weight' => $component['weight'],
'#field_prefix' => empty($component['extra']['field_prefix']) ? NULL : ($filter ? _webform_filter_xss($component['extra']['field_prefix']) : $component['extra']['field_prefix']),
'#field_suffix' => empty($component['extra']['field_suffix']) ? NULL : ($filter ? _webform_filter_xss($component['extra']['field_suffix']) : $component['extra']['field_suffix']),
'#description' => $filter ? _webform_filter_descriptions($component['extra']['description'], $node) : $component['extra']['description'],
'#attributes' => $component['extra']['attributes'],
'#element_validate' => array('_webform_validate_number'),
'#theme_wrappers' => array('webform_element'),
'#min' => $component['extra']['min'],
'#max' => $component['extra']['max'],
'#step' => $component['extra']['step'] ? abs($component['extra']['step']) : '',
'#integer' => $component['extra']['integer'],
'#translatable' => array('title', 'description'),
);
// Flip the min and max properties to make min less than max if needed.
if ($element['#min'] !== '' && $element['#max'] !== '' && $element['#min'] > $element['#max']) {
$max = $element['#min'];
$element['#min'] = $element['#max'];
$element['#max'] = $max;
}
// Ensure #step starts with a zero if a decimal.
if (!is_int($element['#step'] * 1)) {
$decimals = strlen($element['#step']) - strrpos($element['#step'], '.') - 1;
$element['#step'] = sprintf('%1.' . $decimals . 'F', $element['#step']);
}
if ($component['extra']['type'] == 'textfield') {
// Render as textfield.
$element['#type'] = 'webform_number';
// Set the size property based on #max, to ensure consistent behavior for
// browsers that do not support type = number.
if ($element['#max']) {
$element['#size'] = strlen($element['#max']) + 1;
}
}
else {
// Render as select.
$element['#type'] = 'select';
// Create user-specified options list as an array.
$element['#options'] = _webform_number_select_options($component);
// Add default options if using a select list with no default. This trigger's
// Drupal 7's adding of the option for us. See form_process_select().
if ($component['extra']['type'] == 'select' && $element['#default_value'] === '') {
$element['#empty_value'] = '';
}
}
// Set user-entered values.
if (isset($value[0])) {
$element['#default_value'] = $value[0];
}
// Enforce uniqueness.
if ($component['extra']['unique']) {
$element['#element_validate'][] = 'webform_validate_unique';
}
return $element;
}
/**
* Implements _webform_display_component().
*/
function _webform_display_number($component, $value, $format = 'html') {
$empty = !isset($value[0]) || $value[0] === '';
return array(
'#title' => $component['name'],
'#weight' => $component['weight'],
'#theme' => 'webform_display_number',
'#theme_wrappers' => $format == 'html' ? array('webform_element') : array('webform_element_text'),
'#field_prefix' => $empty ? '' : $component['extra']['field_prefix'],
'#field_suffix' => $empty ? '' : $component['extra']['field_suffix'],
'#format' => $format,
'#value' => $empty ? '' : _webform_number_format($component, $value[0]),
'#translatable' => array('title'),
);
}
/**
* Format the output of data for this component.
*/
function theme_webform_display_number($variables) {
$element = $variables['element'];
$prefix = $element['#format'] == 'html' ? filter_xss($element['#field_prefix']) : $element['#field_prefix'];
$suffix = $element['#format'] == 'html' ? filter_xss($element['#field_suffix']) : $element['#field_suffix'];
$value = $element['#format'] == 'html' ? check_plain($element['#value']) : $element['#value'];
return $value !== '' ? ($prefix . $value . $suffix) : ' ';
}
/**
* Implements _webform_analysis_component().
*/
function _webform_analysis_number($component, $sids = array(), $single = FALSE) {
$advanced_stats = $single;
$query = db_select('webform_submitted_data', 'wsd', array('fetch' => PDO::FETCH_ASSOC))
->fields('wsd', array('data'))
->condition('nid', $component['nid'])
->condition('cid', $component['cid']);
if (count($sids)) {
$query->condition('sid', $sids, 'IN');
}
$population = array();
$submissions = 0;
$nonzero = 0;
$not_empty = 0;
$sum = 0;
$result = $query->execute();
foreach ($result as $data) {
$value = trim($data['data']);
if ($value == '') {
$number = 0.0;
}
else {
$number = $value * 1.0;
}
if ($value !== '') {
$not_empty++;
}
if ($number > 0) {
$nonzero++;
$sum += $number;
}
$population[] = $number;
$submissions++;
}
sort($population, SORT_NUMERIC);
// Average and population count.
if ($component['extra']['excludezero']) {
$average = $nonzero ? ($sum / $nonzero) : 0;
$average_title = t('Average !mu excluding zeros/blanks', array('!mu' => $advanced_stats ? '(&mu;)' : ''));
// Sample (sub-set of total population).
$population_count = $nonzero - 1;
$sigma = 'sd';
$description = t('sample');
}
else {
$average = $submissions ? ($sum / $submissions) : 0;
$average_title = t('Average !mu including zeros/blanks', array('!mu' => $advanced_stats ? '(&mu;)' : ''));
// Population.
$population_count = $submissions;
$sigma = '&sigma;';
$description = t('population');
}
// Formatting.
$average = _webform_number_format($component, $average);
$sum = _webform_number_format($component, $sum);
$rows[0] = array(t('Zero/blank'), ($submissions - $nonzero));
$rows[1] = array(t('User entered value'), $not_empty);
$rows[2] = array(t('Sum') . ($advanced_stats ? ' (&Sigma;)' : ''), $sum);
$rows[3] = array($average_title, $average);
if (!$advanced_stats && $sum != 0) {
$rows[4] = array('', l(t('More stats »'), 'node/' . $component['nid'] . '/webform-results/analysis/' . $component['cid']));
}
// Normal distribution information.
if ($advanced_stats && $population_count && $sum != 0) {
// Standard deviation.
$stddev = 0;
foreach($population as $value) {
// Obtain the total of squared variances.
$stddev += pow(($value - $average), 2);
}
if ($population_count > 0) {
$stddev = sqrt($stddev / $population_count);
}
else {
$stddev = sqrt($stddev);
}
// Build normal distribution table rows.
$count = array();
$percent = array();
$limit = array();
$index = 0;
$count[] = 0;
$limit[] = $average - ($stddev * 4);
foreach ($population as $value) {
while ($value >= $limit[$index]) {
$percent[] = number_format($count[$index] / $population_count * 100, 2, '.', '');
$limit[] = $limit[$index] + $stddev;
$index += 1;
if ($limit[$index] == $average) {
$limit[$index] = $limit[$index] + $stddev;
}
$count[$index] = 0;
}
$count[$index] += 1;
}
$percent[] = number_format($count[$index] / $population_count * 100, 2, '.', '');
// Format normal distribution table output.
$stddev = _webform_number_format($component, $stddev);
$low = _webform_number_format($component, $population[0]);
$high = _webform_number_format($component, end($population));
foreach($limit as $key => $value) {
$limit[$key] = _webform_number_format($component, $value);
}
// Column headings (override potential theme uppercase, e.g. Seven in D7).
$header = array(
t('Normal Distribution'),
array('data' => '-4' . $sigma, 'style' => 'text-transform: lowercase;',),
array('data' => '-3' . $sigma, 'style' => 'text-transform: lowercase;',),
array('data' => '-2' . $sigma, 'style' => 'text-transform: lowercase;',),
array('data' => '-1' . $sigma, 'style' => 'text-transform: lowercase;',),
array('data' => '+1' . $sigma, 'style' => 'text-transform: lowercase;',),
array('data' => '+2' . $sigma, 'style' => 'text-transform: lowercase;',),
array('data' => '+3' . $sigma, 'style' => 'text-transform: lowercase;',),
array('data' => '+4' . $sigma, 'style' => 'text-transform: lowercase;',),
);
// Insert row labels.
array_unshift($limit, t('Boundary'));
array_unshift($count, t('Count'));
array_unshift($percent, t('% of !description', array('!description' => $description)));
$output = theme('table', array('header' => $header, 'rows' => array($limit, $count, $percent)));
$rows[4] = array(t('Range'), t('!low to !high', array('!low' => $low, '!high' => $high)));
$rows[5] = array(t('Standard deviation (!sigma)', array('!sigma' => $sigma)), $stddev);
$rows[6] = array(array('data' => $output, 'colspan' => 2));
}
return $rows;
}
/**
* Implements _webform_table_component().
*/
function _webform_table_number($component, $value) {
return isset($value[0]) ? _webform_number_format($component, $value[0]) : '';
}
/**
* Implements _webform_csv_headers_component().
*/
function _webform_csv_headers_number($component, $export_options) {
$header = array();
$header[0] = '';
$header[1] = '';
$header[2] = $component['name'];
return $header;
}
/**
* Implements _webform_csv_data_component().
*/
function _webform_csv_data_number($component, $export_options, $value) {
if (isset($value[0]) && is_numeric($value[0]) && $component['extra']['decimals'] !== '') {
$value[0] = number_format($value[0], $component['extra']['decimals'], '.', '');
}
return isset($value[0]) ? $value[0] : '';
}
/**
* A Drupal Form API Validation function. Validates the entered values from
* number components on the client-side form.
*
* @param $element
* The form element. May either be a select or a webform_number element.
* @param $form_state
* The full form state for the webform.
* @return
* None. Calls a form_set_error if the number is not valid.
*/
function _webform_validate_number($element, &$form_state) {
$value = trim($element['#value']);
form_set_value($element, $value, $form_state);
if ($value != '') {
// Numeric test.
if (is_numeric($value)) {
// Range test.
if ($element['#min'] != '' && $element['#max'] != '') {
// Flip minimum and maximum if needed.
if ($element['#max'] > $element['#min']) {
$min = $element['#min'];
$max = $element['#max'];
}
else {
$min = $element['#max'];
$max = $element['#min'];
}
if ($value > $max || $value < $min) {
form_error($element, t('%name field value of @value should be in the range @min to @max.', array('%name' => $element['#title'], '@value' => $value, '@min' => $min, '@max' => $max)));
}
}
elseif ($element['#max'] != '' && $value > $element['#max']) {
form_error($element, t('%name field value must be less than @max.', array('%name' => $element['#title'], '@max' => $element['#max'])));
}
elseif ($element['#min'] != '' && $value < $element['#min']) {
form_error($element, t('%name field value must be greater than @min.', array('%name' => $element['#title'], '@min' => $element['#min'])));
}
// Integer test.
if ($element['#integer'] && !is_int($value * 1)) {
form_error($element, t('%name field value of @value must be an integer.', array('%name' => $element['#title'], '@value' => $value)));
}
// Step test.
$starting_number = $element['#min'] ? $element['#min'] : 0;
if ($element['#step'] != 0 && fmod($element['#value'] - $starting_number, $element['#step']) != 0) {
$samples = array(
$starting_number,
$starting_number + ($element['#step'] * 1),
$starting_number + ($element['#step'] * 2),
$starting_number + ($element['#step'] * 3),
);
if ($starting_number) {
form_error($element, t('%name field value must be @start plus a multiple of @step. i.e. @samples, etc.', array('%name' => $element['#title'], '@start' => $element['#min'], '@step' => $element['#step'], '@samples' => implode(', ', $samples))));
}
else {
form_error($element, t('%name field value must be a multiple of @step. i.e. @samples, etc.', array('%name' => $element['#title'], '@step' => $element['#step'], '@samples' => implode(', ', $samples))));
}
}
}
else {
form_error($element, t('%name field value of @value must be numeric.', array('%name' => $element['#title'], '@value' => $value)));
}
}
}
/**
* Validation of number edit form items.
*/
function _webform_edit_number_validate($element, &$form_state) {
// Find the value of all related fields to this element.
$parents = $element['#parents'];
$key = array_pop($parents);
$values = $form_state['values'];
foreach ($parents as $parent) {
$values = $values[$parent];
}
switch ($key) {
case 'min':
if ($values['min'] == '') {
if (isset($values['type']) && $values['type'] === 'select') {
form_error($element, t('Minimum is required when using a select list element.'));
}
}
else {
if (!is_numeric($values['min'])) {
form_error($element, t('Minimum must be numeric.'));
}
if ($values['integer'] && !is_int($values['min'] * 1)) {
form_error($element, t('Minimum must have an integer value.'));
}
}
break;
case 'max':
if ($values['max'] == '') {
if (isset($values['type']) && $values['type'] === 'select') {
form_error($element, t('Maximum is required when using a select list element.'));
}
}
else {
if (!is_numeric($values['max'])) {
form_error($element, t('Maximum must be numeric.'));
}
if ($values['integer'] && !is_int($values['max'] * 1)) {
form_error($element, t('Maximum must have an integer value.'));
}
}
break;
case 'step':
if ($values['step'] !== '') {
if (!is_numeric($values['step'])) {
form_error($element, t('Step must be numeric.'));
}
else {
if ($values['integer'] && !is_int($values['step'] * 1)) {
form_error($element, t('Step must have an integer value.'));
}
}
}
break;
}
return TRUE;
}
/**
* Generate select list options.
*/
function _webform_number_select_options($component) {
$options = array();
$step = abs($component['extra']['step']);
// Step is optional and defaults to 1.
$step = empty($step) ? 1 : $step;
// Generate list in correct direction.
$min = $component['extra']['min'];
$max = $component['extra']['max'];
$flipped = FALSE;
if ($max < $min) {
$min = $component['extra']['max'];
$max = $component['extra']['min'];
$flipped = TRUE;
}
for ($f = $min; $f <= $max; $f += $step) {
$options[$f . ''] = $f . '';
}
// TODO: HTML5 browsers apparently do not include the max value if it does
// not line up with step. Restore this if needed in the future.
// Add end limit if it's been skipped due to step.
//if (end($options) != $max) {
// $options[$f] = $max;
//}
if ($flipped) {
$options = array_reverse($options, TRUE);
}
// Apply requisite number formatting.
foreach ($options as $key => $value) {
$options[$key] = _webform_number_format($component, $value);
}
return $options;
}
/**
* Apply number format.
*/
function _webform_number_format($component, $value) {
if (!is_numeric($value)) {
return '';
}
// If no decimal places are specified, do a best guess length of decimals.
$decimals = $component['extra']['decimals'];
if ($decimals === '') {
// If it's an integer, no decimals needed.
if (is_int(($value . '') * 1)) {
$decimals = 0;
}
else {
$decimals = strlen($value) - strrpos($value, '.') - 1;
}
if ($decimals > 4) {
$decimals = 4;
}
}
return number_format($value, $decimals, $component['extra']['point'], $component['extra']['separator']);
}

View File

@@ -0,0 +1,101 @@
<?php
/**
* @file
* Webform module page break component.
*/
/**
* Implements _webform_defaults_component().
*/
function _webform_defaults_pagebreak() {
return array(
'name' => '',
'form_key' => NULL,
'pid' => 0,
'weight' => 0,
'extra' => array(
'private' => FALSE,
'next_page_label' => '',
'prev_page_label' => '',
),
);
}
/**
* Implements _webform_theme_component().
*/
function _webform_theme_pagebreak() {
return array(
'webform_display_pagebreak' => array(
'render element' => 'element',
'file' => 'components/pagebreak.inc',
),
);
}
/**
* Implements _webform_edit_component().
*/
function _webform_edit_pagebreak($component) {
$form = array();
// Force the parent to always be root.
$form['position']['pid'] = array(
'#type' => 'hidden',
'#value' => '0',
);
$form['display'] = array('#type' => 'markup'); // Hide the display options.
$form['extra']['next_page_label'] = array(
'#type' => 'textfield',
'#title' => t('Next page button label'),
'#description' => t('This is used for the <em>Next Page</em> button on the page before this page break. Default: <em>Next Page &gt;</em>'),
'#default_value' => $component['extra']['next_page_label'],
'#size' => 30,
);
$form['extra']['prev_page_label'] = array(
'#type' => 'textfield',
'#title' => t('Prev page button label'),
'#description' => t('This is used for the <em>Prev Page</em> button on the page after this page break. Default: <em>&lt; Prev Page</em>'),
'#default_value' => $component['extra']['prev_page_label'],
'#size' => 30,
);
return $form;
}
/**
* Implements _webform_render_component().
*/
function _webform_render_pagebreak($component, $value = NULL, $filter = TRUE) {
$element = array(
'#type' => 'hidden',
'#value' => $component['name'],
'#weight' => $component['weight'],
);
return $element;
}
/**
* Implements _webform_render_component().
*/
function _webform_display_pagebreak($component, $value = NULL, $format = 'html') {
$element = array(
'#theme' => 'webform_display_pagebreak',
'#title' => $component['name'],
'#weight' => $component['weight'],
'#format' => $format,
'#translatable' => array('title'),
);
return $element;
}
/**
* Format the text output data for this component.
*/
function theme_webform_display_pagebreak($variables) {
$element = $variables['element'];
return $element['#format'] == 'html' ? '<h2 class="webform-page">' . check_plain($element['#title']) . '</h2>' : "--" . $element['#title'] . "--\n";
}

View File

@@ -0,0 +1,981 @@
<?php
/**
* @file
* Webform module multiple select component.
*/
/**
* Implements _webform_defaults_component().
*/
function _webform_defaults_select() {
return array(
'name' => '',
'form_key' => NULL,
'mandatory' => 0,
'pid' => 0,
'weight' => 0,
'value' => '',
'extra' => array(
'items' => '',
'multiple' => NULL,
'aslist' => NULL,
'optrand' => 0,
'other_option' => NULL,
'other_text' => t('Other...'),
'title_display' => 0,
'description' => '',
'custom_keys' => FALSE,
'options_source' => '',
'private' => FALSE,
),
);
}
/**
* Implements _webform_theme_component().
*/
function _webform_theme_select() {
return array(
'webform_display_select' => array(
'render element' => 'element',
'file' => 'components/select.inc',
),
);
}
/**
* Implements _webform_edit_component().
*/
function _webform_edit_select($component) {
$form = array(
'#attached' => array(
'js' => array(
drupal_get_path('module', 'webform') . '/js/select-admin.js' => array('preprocess' => FALSE),
array('data' => array('webform' => array('selectOptionsUrl' => url('webform/ajax/options/' . $component['nid']))), 'type' => 'setting'),
),
),
);
$other = array();
if ($info = _webform_select_options_info()) {
$options = array('' => t('None'));
foreach ($info as $name => $source) {
$options[$name] = $source['title'];
}
$other['options_source'] = array(
'#title' => t('Load a pre-built option list'),
'#type' => 'select',
'#options' => $options,
'#default_value' => $component['extra']['options_source'],
'#weight' => 1,
'#description' => t('Use a pre-built list of options rather than entering options manually. Options will not be editable if using pre-built list.'),
'#parents' => array('extra', 'options_source'),
'#weight' => 5,
);
}
if (module_exists('select_or_other')) {
$other['other_option'] = array(
'#type' => 'checkbox',
'#title' => t('Allow "Other..." option'),
'#default_value' => $component['extra']['other_option'],
'#description' => t('Check this option if you want to allow users to enter an option not on the list.'),
'#parents' => array('extra', 'other_option'),
'#weight' => 2,
);
$other['other_text'] = array(
'#type' => 'textfield',
'#title' => t('Text for "Other..." option'),
'#default_value' => $component['extra']['other_text'],
'#description' => t('If allowing other options, enter text to be used for other-enabling option.'),
'#parents' => array('extra', 'other_text'),
'#weight' => 3,
);
}
if (module_exists('options_element')) {
$options = _webform_select_options($component, FALSE, FALSE);
$form['items'] = array(
'#type' => 'fieldset',
'#title' => t('Options'),
'#collapsible' => TRUE,
'#attributes' => array('class' => array('webform-options-element')),
'#element_validate' => array('_webform_edit_validate_options'),
'#weight' => 2,
);
$form['items']['options'] = array(
'#type' => 'options',
'#limit' => 500,
'#optgroups' => $component['extra']['aslist'],
'#multiple' => $component['extra']['multiple'],
'#multiple_toggle' => t('Multiple'),
'#default_value' => $component['value'],
'#options' => $options,
'#options_readonly' => !empty($component['extra']['options_source']),
'#key_type' => 'mixed',
'#key_type_toggle' => t('Customize keys (Advanced)'),
'#key_type_toggled' => $component['extra']['custom_keys'],
'#default_value_pattern' => '^%.+\[.+\]$',
'#weight' => 1,
);
$form['items']['options']['option_settings'] = $other;
}
else {
$form['extra']['items'] = array(
'#type' => 'textarea',
'#title' => t('Options'),
'#default_value' => $component['extra']['items'],
'#description' => t('<strong>Key-value pairs MUST be specified as "safe_key|Some readable option"</strong>. Use of only alphanumeric characters and underscores is recommended in keys. One option per line. Option groups may be specified with &lt;Group Name&gt;. &lt;&gt; can be used to insert items at the root of the menu after specifying a group.') . theme('webform_token_help'),
'#cols' => 60,
'#rows' => 5,
'#weight' => 0,
'#required' => TRUE,
'#wysiwyg' => FALSE,
'#element_validate' => array('_webform_edit_validate_select'),
);
if (!empty($component['extra']['options_source'])) {
$form['extra']['items']['#attributes'] = array('readonly' => 'readonly');
}
$form['extra'] = array_merge($form['extra'], $other);
$form['value'] = array(
'#type' => 'textfield',
'#title' => t('Default value'),
'#default_value' => $component['value'],
'#description' => t('The default value of the field identified by its key. For multiple selects use commas to separate multiple defaults.') . theme('webform_token_help'),
'#size' => 60,
'#maxlength' => 1024,
'#weight' => 0,
);
$form['extra']['multiple'] = array(
'#type' => 'checkbox',
'#title' => t('Multiple'),
'#default_value' => $component['extra']['multiple'],
'#description' => t('Check this option if the user should be allowed to choose multiple values.'),
'#weight' => 0,
);
}
$form['display']['aslist'] = array(
'#type' => 'checkbox',
'#title' => t('Listbox'),
'#default_value' => $component['extra']['aslist'],
'#description' => t('Check this option if you want the select component to be displayed as a select list box instead of radio buttons or checkboxes. Option groups (nested options) are only supported with listbox components.'),
'#parents' => array('extra', 'aslist'),
);
$form['display']['optrand'] = array(
'#type' => 'checkbox',
'#title' => t('Randomize options'),
'#default_value' => $component['extra']['optrand'],
'#description' => t('Randomizes the order of the options when they are displayed in the form.'),
'#parents' => array('extra', 'optrand'),
);
return $form;
}
/**
* Element validation callback. Ensure keys are not duplicated.
*/
function _webform_edit_validate_select($element, &$form_state) {
// Check for duplicate key values to prevent unexpected data loss. Require
// all options to include a safe_key.
if (!empty($element['#value'])) {
$lines = explode("\n", trim($element['#value']));
$existing_keys = array();
$duplicate_keys = array();
$missing_keys = array();
$long_keys = array();
$group = '';
foreach ($lines as $line) {
$matches = array();
$line = trim($line);
if (preg_match('/^\<([^>]*)\>$/', $line, $matches)) {
$group = $matches[1];
$key = NULL; // No need to store group names.
}
elseif (preg_match('/^([^|]*)\|(.*)$/', $line, $matches)) {
$key = $matches[1];
if (strlen($key) > 128) {
$long_keys[] = $key;
}
}
else {
$missing_keys[] = $line;
}
if (isset($key)) {
if (isset($existing_keys[$group][$key])) {
$duplicate_keys[$key] = $key;
}
else {
$existing_keys[$group][$key] = $key;
}
}
}
if (!empty($missing_keys)) {
form_error($element, t('Every option must have a key specified. Specify each option as "safe_key|Some readable option".'));
}
if (!empty($long_keys)) {
form_error($element, t('Option keys must be less than 128 characters. The following keys exceed this limit:') . theme('item_list', $long_keys));
}
if (!empty($duplicate_keys)) {
form_error($element, t('Options within the select list must be unique. The following keys have been used multiple times:') . theme('item_list', array('items' => $duplicate_keys)));
}
// Set the listbox option if needed.
if (empty($missing_keys) && empty($long_keys) && empty($duplicate_keys)) {
$options = _webform_select_options_from_text($element['#value']);
_webform_edit_validate_set_aslist($options, $form_state);
}
}
return TRUE;
}
/**
* Set the appropriate webform values when using the options element module.
*/
function _webform_edit_validate_options($element, &$form_state) {
$key = end($element['#parents']);
$element_options = $form_state['values'][$key]['options'];
unset($form_state['values'][$key]);
$form_state['values']['extra'][$key] = form_options_to_text($element_options['options'], 'custom');
// Options saved for select components.
if ($key == 'items') {
$form_state['values']['extra']['multiple'] = $element_options['multiple'];
$form_state['values']['extra']['custom_keys'] = $element_options['custom_keys'];
$form_state['values']['value'] = is_array($element_options['default_value']) ? implode(', ', $element_options['default_value']) : $element_options['default_value'];
// Set the listbox option if needed.
_webform_edit_validate_set_aslist($element_options['options'], $form_state);
}
// Options saved for grid components.
else {
$form_state['values']['extra']['custom_' . rtrim($key, 's') . '_keys'] = $element_options['custom_keys'];
}
}
/**
* Ensure "aslist" is used for option groups. Called from options validations.
*/
function _webform_edit_validate_set_aslist($options, &$form_state) {
if (empty($form_state['values']['extra']['aslist']) && !empty($options)) {
foreach ($options as $option) {
if (is_array($option)) {
$form_state['values']['extra']['aslist'] = 1;
drupal_set_message(t('The component %name has automatically been set to display as a listbox in order to support option groups.', array('%name' => $form_state['values']['name'])), 'warning');
break;
}
}
}
}
/**
* Implements _webform_render_component().
*/
function _webform_render_select($component, $value = NULL, $filter = TRUE) {
$node = isset($component['nid']) ? node_load($component['nid']) : NULL;
$element = array(
'#title' => $filter ? _webform_filter_xss($component['name']) : $component['name'],
'#title_display' => $component['extra']['title_display'] ? $component['extra']['title_display'] : 'before',
'#required' => $component['mandatory'],
'#weight' => $component['weight'],
'#description' => $filter ? _webform_filter_descriptions($component['extra']['description'], $node) : $component['extra']['description'],
'#theme_wrappers' => array('webform_element'),
'#pre_render' => array(), // Needed to disable double-wrapping of radios and checkboxes.
'#translatable' => array('title', 'description', 'options'),
);
// Convert the user-entered options list into an array.
$default_value = $filter ? _webform_filter_values($component['value'], $node, NULL, NULL, FALSE) : $component['value'];
$options = _webform_select_options($component, !$component['extra']['aslist'], $filter);
if ($component['extra']['optrand']) {
_webform_shuffle_options($options);
}
// Add default options if using a select list with no default. This trigger's
// Drupal 7's adding of the option for us. See @form_process_select().
if ($component['extra']['aslist'] && !$component['extra']['multiple'] && $default_value === '') {
$element['#empty_value'] = '';
}
// Set the component options.
$element['#options'] = $options;
// Set the default value.
if (isset($value)) {
if ($component['extra']['multiple']) {
// Set the value as an array.
$element['#default_value'] = array();
foreach ((array) $value as $key => $option_value) {
$element['#default_value'][] = $option_value;
}
}
else {
// Set the value as a single string.
$element['#default_value'] = '';
foreach ((array) $value as $option_value) {
$element['#default_value'] = $option_value;
}
}
}
elseif ($default_value !== '') {
// Convert default value to a list if necessary.
if ($component['extra']['multiple']) {
$varray = explode(',', $default_value);
foreach ($varray as $key => $v) {
$v = trim($v);
if ($v !== '') {
$element['#default_value'][] = $v;
}
}
}
else {
$element['#default_value'] = $default_value;
}
}
elseif ($component['extra']['multiple']) {
$element['#default_value'] = array();
}
if ($component['extra']['other_option'] && module_exists('select_or_other')) {
// Set display as a select_or_other element:
$element['#type'] = 'select_or_other';
$element['#other'] = !empty($component['extra']['other_text']) ? check_plain($component['extra']['other_text']) : t('Other...');
$element['#other_title'] = $element['#title'] . ' ' . $element['#other'];
$element['#other_title_display'] = 'invisible';
$element['#other_unknown_defaults'] = 'other';
$element['#other_delimiter'] = ', ';
// Merge in Webform's #process function for Select or other.
$element['#process'] = array_merge(element_info_property('select_or_other', '#process'), array('webform_expand_select_or_other'));
if ($component['extra']['multiple']) {
$element['#multiple'] = TRUE;
$element['#select_type'] = 'checkboxes';
}
else {
$element['#multiple'] = FALSE;
$element['#select_type'] = 'radios';
}
if ($component['extra']['aslist']) {
$element['#select_type'] = 'select';
}
}
elseif ($component['extra']['aslist']) {
// Set display as a select list:
$element['#type'] = 'select';
if ($component['extra']['multiple']) {
$element['#size'] = 4;
$element['#multiple'] = TRUE;
}
}
else {
if ($component['extra']['multiple']) {
// Set display as a checkbox set.
$element['#type'] = 'checkboxes';
$element['#theme_wrappers'] = array_merge(array('checkboxes'), $element['#theme_wrappers']);
$element['#process'] = array_merge(element_info_property('checkboxes', '#process'), array('webform_expand_select_ids'));
// Entirely replace the normal expand checkboxes with our custom version.
// This helps render checkboxes in multipage forms.
$process_key = array_search('form_process_checkboxes', $element['#process']);
$element['#process'][$process_key] = 'webform_expand_checkboxes';
}
else {
// Set display as a radio set.
$element['#type'] = 'radios';
$element['#theme_wrappers'] = array_merge(array('radios'), $element['#theme_wrappers']);
$element['#process'] = array_merge(element_info_property('radios', '#process'), array('webform_expand_select_ids'));
}
}
return $element;
}
/**
* Process function to ensure select_or_other elements validate properly.
*/
function webform_expand_select_or_other($element) {
// Disable validation for back-button and save draft.
$element['select']['#validated'] = TRUE;
$element['select']['#webform_validated'] = FALSE;
$element['other']['#validated'] = TRUE;
$element['other']['#webform_validated'] = FALSE;
// The Drupal FAPI does not support #title_display inline so we need to move
// to a supported value here to be compatible with select_or_other.
$element['select']['#title_display'] = $element['#title_display'] === 'inline' ? 'before' : $element['#title_display'];
// If the default value contains "select_or_other" (the key of the select
// element for the "other..." choice), discard it and set the "other" value.
if (is_array($element['#default_value']) && in_array('select_or_other', $element['#default_value'])) {
$key = array_search('select_or_other', $element['#default_value']);
unset($element['#default_value'][$key]);
$element['#default_value'] = array_values($element['#default_value']);
$element['other']['#default_value'] = implode(', ', $element['#default_value']);
}
// Sanitize the options in Select or other check boxes and radio buttons.
if ($element['#select_type'] == 'checkboxes' || $element['#select_type'] == 'radios') {
$element['select']['#process'] = array_merge(element_info_property($element['#select_type'], '#process'), array('webform_expand_select_ids'));
}
return $element;
}
/**
* Drupal 6 hack that properly *renders* checkboxes in multistep forms. This is
* different than the value hack needed in Drupal 5, which is no longer needed.
*/
function webform_expand_checkboxes($element) {
// Elements that have a value set are already in the form structure cause
// them not to be written when the expand_checkboxes function is called.
$default_value = array();
foreach (element_children($element) as $key) {
if (isset($element[$key]['#default_value'])) {
$default_value[$key] = $element[$key]['#default_value'];
unset($element[$key]);
}
}
$element = form_process_checkboxes($element);
// Escape the values of checkboxes.
foreach (element_children($element) as $key) {
$element[$key]['#return_value'] = check_plain($element[$key]['#return_value']);
$element[$key]['#name'] = $element['#name'] . '[' . $element[$key]['#return_value'] . ']';
}
foreach ($default_value as $key => $val) {
$element[$key]['#default_value'] = $val;
}
return $element;
}
/**
* FAPI process function to rename IDs attached to checkboxes and radios.
*/
function webform_expand_select_ids($element) {
$id = $element['#id'] = str_replace('_', '-', _webform_safe_name(strip_tags($element['#id'])));
$delta = 0;
foreach (element_children($element) as $key) {
$delta++;
// Convert the #id for each child to a safe name, regardless of key.
$element[$key]['#id'] = $id . '-' . $delta;
// Prevent scripts or CSS in the labels for each checkbox or radio.
$element[$key]['#title'] = _webform_filter_xss($element[$key]['#title']);
}
return $element;
}
/**
* Implements _webform_display_component().
*/
function _webform_display_select($component, $value, $format = 'html') {
return array(
'#title' => $component['name'],
'#weight' => $component['weight'],
'#multiple' => $component['extra']['multiple'],
'#theme' => 'webform_display_select',
'#theme_wrappers' => $format == 'html' ? array('webform_element') : array('webform_element_text'),
'#format' => $format,
'#options' => _webform_select_options($component, !$component['extra']['aslist']),
'#value' => (array) $value,
'#translatable' => array('title', 'options'),
);
}
/**
* Implements _webform_submit_component().
*
* Convert FAPI 0/1 values into something saveable.
*/
function _webform_submit_select($component, $value) {
// Build a list of all valid keys expected to be submitted.
$options = _webform_select_options($component, TRUE);
$return = NULL;
if (is_array($value)) {
$return = array();
foreach ($value as $key => $option_value) {
// Handle options that are specified options.
if ($option_value !== '' && isset($options[$option_value])) {
// Checkboxes submit an integer value of 0 when unchecked. A checkbox
// with a value of '0' is valid, so we can't use empty() here.
if ($option_value === 0 && !$component['extra']['aslist'] && $component['extra']['multiple']) {
unset($value[$option_value]);
}
else {
$return[] = $option_value;
}
}
// Handle options that are added through the "other" field. Specifically
// exclude the "select_or_other" value, which is added by the select list.
elseif ($component['extra']['other_option'] && module_exists('select_or_other') && $option_value != 'select_or_other') {
$return[] = $option_value;
}
}
}
elseif (is_string($value)) {
$return = $value;
}
return $return;
}
/**
* Format the text output for this component.
*/
function theme_webform_display_select($variables) {
$element = $variables['element'];
// Flatten the list of options so we can get values easily. These options
// may be translated by hook_webform_display_component_alter().
$options = array();
foreach ($element['#options'] as $key => $value) {
if (is_array($value)) {
foreach ($value as $subkey => $subvalue) {
$options[$subkey] = $subvalue;
}
}
else {
$options[$key] = $value;
}
}
$items = array();
if ($element['#multiple']) {
foreach ((array) $element['#value'] as $option_value) {
if ($option_value !== '') {
// Administer provided values.
if (isset($options[$option_value])) {
$items[] = $element['#format'] == 'html' ? _webform_filter_xss($options[$option_value]) : $options[$option_value];
}
// User-specified in the "other" field.
else {
$items[] = $element['#format'] == 'html' ? check_plain($option_value) : $option_value;
}
}
}
}
else {
if (isset($element['#value'][0]) && $element['#value'][0] !== '') {
// Administer provided values.
if (isset($options[$element['#value'][0]])) {
$items[] = $element['#format'] == 'html' ? _webform_filter_xss($options[$element['#value'][0]]) : $options[$element['#value'][0]];
}
// User-specified in the "other" field.
else {
$items[] = $element['#format'] == 'html' ? check_plain($element['#value'][0]) : $element['#value'][0];
}
}
}
if ($element['#format'] == 'html') {
$output = count($items) > 1 ? theme('item_list', array('items' => $items)) : (isset($items[0]) ? $items[0] : ' ');
}
else {
if (count($items) > 1) {
foreach ($items as $key => $item) {
$items[$key] = ' - ' . $item;
}
$output = implode("\n", $items);
}
else {
$output = isset($items[0]) ? $items[0] : ' ';
}
}
return $output;
}
/**
* Implements _webform_analysis_component().
*/
function _webform_analysis_select($component, $sids = array(), $single = FALSE) {
$options = _webform_select_options($component, TRUE);
$show_other_results = $single;
$sid_placeholders = count($sids) ? array_fill(0, count($sids), "'%s'") : array();
$sid_filter = count($sids) ? " AND sid IN (" . implode(",", $sid_placeholders) . ")" : "";
$option_operator = $show_other_results ? 'NOT IN' : 'IN';
$query = db_select('webform_submitted_data', 'wsd', array('fetch' => PDO::FETCH_ASSOC))
->fields('wsd', array('data'))
->condition('nid', $component['nid'])
->condition('cid', $component['cid'])
->condition('data', '', '<>')
->condition('data', array_keys($options), $option_operator)
->groupBy('data');
$query->addExpression('COUNT(data)', 'datacount');
if (count($sids)) {
$query->condition('sid', $sids, 'IN');
}
$count_query = db_select('webform_submitted_data', 'wsd', array('fetch' => PDO::FETCH_ASSOC))
->condition('nid', $component['nid'])
->condition('cid', $component['cid'])
->condition('data', '', '<>');
$count_query->addExpression('COUNT(*)', 'datacount');
if (count($sids)) {
$count_query->condition('sid', $sids, 'IN');
}
$result = $query->execute();
$rows = array();
$normal_count = 0;
foreach ($result as $data) {
$display_option = $single ? $data['data'] : $options[$data['data']];
$rows[$data['data']] = array(_webform_filter_xss($display_option), $data['datacount']);
$normal_count += $data['datacount'];
}
if (!$show_other_results) {
// Order the results according to the normal options array.
$ordered_rows = array();
foreach (array_intersect_key($options, $rows) as $key => $label) {
$ordered_rows[] = $rows[$key];
}
// Add a row for any unknown or user-entered values.
if ($component['extra']['other_option']) {
$full_count = $count_query->execute()->fetchField();
$other_count = $full_count - $normal_count;
$display_option = !empty($component['extra']['other_text']) ? check_plain($component['extra']['other_text']) : t('Other...');
$other_text = $other_count ? $other_count . ' (' . l(t('view'), 'node/' . $component['nid'] . '/webform-results/analysis/' . $component['cid']) . ')' : $other_count;
$ordered_rows[] = array($display_option, $other_text);
}
$rows = $ordered_rows;
}
return $rows;
}
/**
* Implements _webform_table_component().
*/
function _webform_table_select($component, $value) {
// Convert submitted 'safe' values to un-edited, original form.
$options = _webform_select_options($component, TRUE);
$value = (array) $value;
$items = array();
// Set the value as a single string.
foreach ($value as $option_value) {
if ($option_value !== '') {
if (isset($options[$option_value])) {
$items[] = _webform_filter_xss($options[$option_value]);
}
else {
$items[] = check_plain($option_value);
}
}
}
return implode('<br />', $items);
}
/**
* Implements _webform_csv_headers_component().
*/
function _webform_csv_headers_select($component, $export_options) {
$headers = array(
0 => array(),
1 => array(),
2 => array(),
);
if ($component['extra']['multiple'] && $export_options['select_format'] == 'separate') {
$headers[0][] = '';
$headers[1][] = $component['name'];
$items = _webform_select_options($component, TRUE, FALSE);
if ($component['extra']['other_option']) {
$other_label = !empty($component['extra']['other_text']) ? check_plain($component['extra']['other_text']) : t('Other...');
$items[$other_label] = $other_label;
}
$count = 0;
foreach ($items as $key => $item) {
// Empty column per sub-field in main header.
if ($count != 0) {
$headers[0][] = '';
$headers[1][] = '';
}
if ($export_options['select_keys']) {
$headers[2][] = $key;
}
else {
$headers[2][] = $item;
}
$count++;
}
}
else {
$headers[0][] = '';
$headers[1][] = '';
$headers[2][] = $component['name'];
}
return $headers;
}
/**
* Implements _webform_csv_data_component().
*/
function _webform_csv_data_select($component, $export_options, $value) {
$options = _webform_select_options($component, TRUE, FALSE);
$return = array();
if ($component['extra']['multiple']) {
foreach ($options as $key => $item) {
$index = array_search($key, (array) $value);
if ($index !== FALSE) {
if ($export_options['select_format'] == 'separate') {
$return[] = 'X';
}
else {
$return[] = $export_options['select_keys'] ? $key : $item;
}
unset($value[$index]);
}
elseif ($export_options['select_format'] == 'separate') {
$return[] = '';
}
}
// Any remaining items in the $value array will be user-added options.
if ($component['extra']['other_option']) {
$return[] = count($value) ? implode(',', $value) : '';
}
}
else {
$key = $value[0];
if ($export_options['select_keys']) {
$return = $key;
}
else {
$return = isset($options[$key]) ? $options[$key] : $key;
}
}
if ($component['extra']['multiple'] && $export_options['select_format'] == 'compact') {
$return = implode(',', (array) $return);
}
return $return;
}
/**
* Menu callback; Return a predefined list of select options as JSON.
*/
function webform_select_options_ajax($source_name = '') {
$info = _webform_select_options_info();
$component['extra']['options_source'] = $source_name;
if ($source_name && isset($info[$source_name])) {
$options = _webform_select_options_to_text(_webform_select_options($component, !$component['extra']['aslist'], FALSE));
}
else {
$options = '';
}
$return = array(
'elementId' => module_exists('options_element') ? 'edit-items-options-options-field-widget' : 'edit-extra-items',
'options' => $options,
);
drupal_json_output($return);
}
/**
* Generate a list of options for a select list.
*/
function _webform_select_options($component, $flat = FALSE, $filter = TRUE) {
if ($component['extra']['options_source']) {
$options = _webform_select_options_callback($component['extra']['options_source'], $component, $flat, $filter);
}
else {
$options = _webform_select_options_from_text($component['extra']['items'], $flat, $filter);
}
return isset($options) ? $options : array();
}
/**
* Load Webform select option info from 3rd party modules.
*/
function _webform_select_options_info() {
static $info;
if (!isset($info)) {
$info = array();
foreach (module_implements('webform_select_options_info') as $module) {
$additions = module_invoke($module, 'webform_select_options_info');
foreach ($additions as $key => $addition) {
$additions[$key]['module'] = $module;
}
$info = array_merge($info, $additions);
}
drupal_alter('webform_select_options_info', $info);
}
return $info;
}
/**
* Execute a select option callback.
*
* @param $name
* The name of the options group.
* @param $component
* The full Webform component.
* @param $flat
* Whether the information returned should exclude any nested groups.
* @param $filter
* Whether information returned should be sanitized. Defaults to TRUE.
*/
function _webform_select_options_callback($name, $component, $flat = FALSE, $filter = TRUE) {
$info = _webform_select_options_info();
// Include any necessary files.
if (isset($info[$name]['file'])) {
$pathinfo = pathinfo($info[$name]['file']);
$path = ($pathinfo['dirname'] ? $pathinfo['dirname'] . '/' : '') . basename($pathinfo['basename'], '.' . $pathinfo['extension']);
module_load_include($pathinfo['extension'], $info[$name]['module'], $path);
}
// Execute the callback function.
if (isset($info[$name]['options callback']) && function_exists($info[$name]['options callback'])) {
$function = $info[$name]['options callback'];
$arguments = array();
if (isset($info[$name]['options arguments'])) {
$arguments = $info[$name]['options arguments'];
}
return $function($component, $flat, $filter, $arguments);
}
}
/**
* Utility function to split user-entered values from new-line separated
* text into an array of options.
*
* @param $text
* Text to be converted into a select option array.
* @param $flat
* Optional. If specified, return the option array and exclude any optgroups.
* @param $filter
* Optional. Whether or not to filter returned values.
*/
function _webform_select_options_from_text($text, $flat = FALSE, $filter = TRUE) {
static $option_cache = array();
// Keep each processed option block in an array indexed by the MD5 hash of
// the option text and the value of the $flat variable.
$md5 = md5($text);
// Check if this option block has been previously processed.
if (!isset($option_cache[$flat][$md5])) {
$options = array();
$rows = array_filter(explode("\n", trim($text)));
$group = NULL;
foreach ($rows as $option) {
$option = trim($option);
/**
* If the Key of the option is within < >, treat as an optgroup
*
* <Group 1>
* creates an optgroup with the label "Group 1"
*
* <>
* Unsets the current group, allowing items to be inserted at the root element.
*/
if (preg_match('/^\<([^>]*)\>$/', $option, $matches)) {
if (empty($matches[1])) {
unset($group);
}
elseif (!$flat) {
$group = $filter ? _webform_filter_values($matches[1], NULL, NULL, NULL, FALSE) : $matches[1];
}
}
elseif (preg_match('/^([^|]+)\|(.*)$/', $option, $matches)) {
$key = $filter ? _webform_filter_values($matches[1], NULL, NULL, NULL, FALSE) : $matches[1];
$value = $filter ? _webform_filter_values($matches[2], NULL, NULL, NULL, FALSE) : $matches[2];
isset($group) ? $options[$group][$key] = $value : $options[$key] = $value;
}
else {
$filtered_option = $filter ? _webform_filter_values($option, NULL, NULL, NULL, FALSE) : $option;
isset($group) ? $options[$group][$filtered_option] = $filtered_option : $options[$filtered_option] = $filtered_option;
}
}
$option_cache[$flat][$md5] = $options;
}
// Return our options from the option_cache array.
return $option_cache[$flat][$md5];
}
/**
* Convert an array of options into text.
*/
function _webform_select_options_to_text($options) {
$output = '';
$previous_key = FALSE;
foreach ($options as $key => $value) {
// Convert groups.
if (is_array($value)) {
$output .= '<' . $key . '>' . "\n";
foreach ($value as $subkey => $subvalue) {
$output .= $subkey . '|' . $subvalue . "\n";
}
$previous_key = $key;
}
// Typical key|value pairs.
else {
// Exit out of any groups.
if (isset($options[$previous_key]) && is_array($options[$previous_key])) {
$output .= "<>\n";
}
// Skip empty rows.
if ($options[$key] !== '') {
$output .= $key . '|' . $value . "\n";
}
$previous_key = $key;
}
}
return $output;
}
/**
* Utility function to shuffle an array while preserving key-value pairs.
*/
function _webform_shuffle_options(&$array) {
// First shuffle the array keys, then use them as the basis for ordering
// the options.
$aux = array();
$keys = array_keys($array);
shuffle($keys);
foreach ($keys as $key) {
$aux[$key] = $array[$key];
}
$array = $aux;
}

Some files were not shown because too many files have changed in this diff Show More