I'm having difficulty figuring out how to write a module with a form that uploads files, in Drupal 6. Can anyone explain this, or point me to a good example/documentation discussing it?
EDIT:
Here is entirely what I am trying to do:
User uploads a .csv
Module reads the first line of the file to get fields
User matches csv fields with db fields
Each csv line is saved as a node (preview it first)
So far, I can do 1, 2, and 4 successfully. But it's unclear exactly how the steps should interact with each other ($form_state['redirect']? how should that be used?), and what the best practices are. And for 3, should I save that as session data?
How do I pass the file data between the various steps?
I know that node_import exists, but it's never worked for me, and my bug requests go ignored.
2nd EDIT: I used this at the start and end of every page that needed to deal with the file:
$file = unserialize($_SESSION['file']);
//alter $file object
$_SESSION['file'] = serialize(file);
I'm not sure it it's best practices, but it's been working.
This is not too difficult, you can see some info here. An example of a form with only a file upload.
function myform_form($form_state) {
$form = array('#attributes' => array('enctype' => 'multipart/form-data'));
$form['file'] = array(
'#type' => 'file',
'#title' => t('Upload video'),
'#size' => 48,
'#description' => t('Pick a video file to upload.'),
);
return $form;
}
EDIT:
Now to save the file use the file_save_upload function:
function myform_form_submit($form, $form_state) {
$validators = array();
$file = file_save_upload('file', $validators, 'path');
file_set_status($file, FILE_STATUS_PERMANENT);
}
2nd EDIT:
There's a lot of questions and ways to do the things you described. I wont go to much into the actual code of how to handle a csv file. What I would suggest is that you use the file id to keep track of the file. That would enable you to make urls that take a fid and use that to load the file you want to work on.
To get from your form to the next step, you can use the #redirect form property to get your users to the next step. From there is really depends how you do things, what you'll need to do.
Related
I am currently using simple_html_dom to parse some MP3 files from another website, and store them onto my own server. However I've noticed that some of them contain a tag which indicates the location they originated from within the comment portion of the ID3 properties.
I need to make this website, say my own websites name. However, the only solution that I've found to doing this with PHP is beyond complicated using something called GETID3.php You can view the github link by clicking the name.
I don't really understand the documentation can someone help me find an easier way of doing this please?
Here's the part of my code that matters, I guess.
$mp3title = ''.$thetitle.' - Oursite.com';
file_put_contents($DPATH.'/temp/'.$mp3title.'.mp3',file_get_contents($filepath));
$file = $DPATH.'/temp/'.$mp3title.'.mp3';
Provided you're not interested in also updating the image of the file, you can look into just using something simple like the default php function id3_set_tag however for more complex usages like updating the artwork then you're going to have to use the library you mentioned before.
$data = array(
"title" => "Re:Start",
"artist" => "Re:\Legion",
"comment" => "YourWebsiteName.com"
);
$result = id3_set_tag($DPATH.'/temp/'.$mp3title.'.mp3', $data, ID3_V1_0 );
if ($result === true) {
echo "Tag successfully updated\n";
}
this is my first question, which I can't figure out how to make relevant to other people as per the guidelines. I suppose just a question at the end as to whether a noob should ever attempt to meddle with code they don't fully understand.
My site depends on an xml database generated elsewhere which is spliced into site-specific format, set up by the original developer. The system generating the database changed a tag from "contact" to "person", breaking the data formula for the splicing. (Grr.)
I thought I had fixed it, because I changed the tag in the receiving file, but the splicer has just stopped completely. (Basically, I don’t really know enough about the site/coding to have attempted to make these changes. But I thought I could get away with it!)
This is what I understand happens:
1. every night we send an xml file into folder
2. a php file reformats the raw xml with SimpleXmlIterator.
3. that sends the reformatted file to a staging.sql file.
4. that sends it to the right place for the site to load it nightly.
Step 4 is still happening, but the site is using the same data over and over. The new data is just not making it through step 2 and 3.
This is what I did (I just commented out the original code. I'm "SOC"):
$authors = array();
foreach ($author_array as $arr) {
$bio = ($arr['copy_biography']) ? nl2br(htmlspecialchars($arr['copy_biography'], ENT_QUOTES)) : '';
// SOC changed $author_title = $arr['contact_first_name'] .' '. $arr['contact_surname'];
$author_title = $arr['person_first_name'] .' '. $arr['person_surname'];
$authors[] = array(
'title' => $author_title,
'author_id' => $arr['id'],
// SOC changed from this to the below 'fname' => $arr['contact_first_name'],
'fname' => $arr['person_first_name'],
// SOC changed from this to the below 'lname' => $arr['contact_surname'],
'lname' => $arr['person_surname'],
// SOC ditto 'website' => $arr['contact_web_page'],
'website' => $arr['person_web_page'],
'bio' => $bio,
// SOC ditto 'twitter' => $arr['contact_fax']
'twitter' => $arr['person_fax']
);
}
$authors = generate_valid_xml_from_array($authors);
$authors_xml = '/var/www/hotkeybooks/biblio/authors_import.xml';
$authorfile = fopen($authors_xml,'w') or die("can't open file");
fwrite($authorfile,$authors);
fclose($authorfile);
//make the files readable
exec('chmod 444 /var/www/hotkeybooks/biblio/*.xml');
I also changed “contact” to “person” the staging.sql and the staging.tgz.
-- ----------------------------
-- Records of `exp_dd_doc_sections`
-- ----------------------------
BEGIN;
INSERT INTO `exp_dd_doc_sections` VALUES (…….<td>contact_first_name, contact_surname</td>\n <td>Text Input</td>\n <td>Would enter author full name, this field would only be used for admin purposes.</td>\n <td>y</td>\n </tr>\n <tr>\n <td>Author Biblio ID</td>\n <td>author_biblio_id</td>\n <td>id</td>\n <td>Text Input</td>\n <td>Used for relationship building and reference only</td>\n <td></td>\n </tr>\n <tr>\n <td>Author First Name</td>\n <td>author_fname</td>\n <td>contact_first_name</td>\n <td>Text Input</td>\n <td></td>\n <td></td>\n </tr>\n <tr>\n <td>Author Last Name</td>\n <td>author_lname</td>\n <td>contact_surname</td>\n <td>Text Input</td>\n <td></td>\n <td></td>\n </tr>\n ………)
Does anyone know which bit of what I did broke the system, and what I can do to restore it?
I have tried overwriting my changes with the original files, but that hasn’t helped.
Any guidance would be greatly appreciated.
Sounds like you need some basic troubleshooting.
Perhaps your parsing is working correctly but the transfer between the various locations is failing due to file permissions or something.
Working backwards:
Can you confirm that the file that is transferred in step 4 is a new file? Does it have the expected modified date? Does it have the expected data?
Can you confirm that the file in step 3 staging.sql is a new file with the expected modified date? Does it have the expected data?
Can you confirm that the file created in step 2 is a new file with the expected date and data?
Do you seeing anything in your error log to suggest that anything in the script has failed?
I have a file called functions.php.
It contains a lot of data in over 3000 lines.
Somewhere in the middle of this file there is code:
/*****************************************
My Custom Code
*****************************************/
if ( function_exists('my_code') )
my_code(array(
'name' => 'First instance',
'description' => 'Hello, hello.',
));
if ( function_exists('my_code') )
my_code(array(
'name' => 'Second instance',
'description' => 'Haha :)',
));
I'm listing all my_code arrays and I'm getting:
First Instance
Second Instance
Now, what I want to achieve, is, when user clicks X next to "First instance" PHP opens functions.php file in the background, finds the exact function and deletes it without touching anything else.
So after deleting "First Instance" functions.php file should look like this:
/*****************************************
My Custom Code
*****************************************/
if ( function_exists('my_code') )
my_code(array(
'name' => 'Second instance',
'description' => 'Haha :)',
));
Any idea how to achieve this? I know how to open files, write, delete, but I'm not sure how to wipe out not only a single line but a few lines around? :)
If your code is always in the format you described you could read each 5 lines from your file and if it's the instance you want to keep, output them to a string. Then write the string back to the original file.
But again yes, code modifying code IS PAIN. Storing your instances in a data structure such as databases or a formatted file is much better.
I think the best way would be to open the file and loop through the lines. You'll need to match each line of your function, or you would need match the first line and track the number of open and close brackets { } to know when you've reached the end of it.
If a line doesn't match you write that out to a new file. If it does match you ignore it. Then finally you make an system call to do a syntax check on the new file (in case something went wrong with your line matching):
system( "php -l newfile.php", &$retval );
Then check the return value $retval to make sure it was ok (it will be exactly equal to 0). If it is okay then you overwrite functions.php with your new file.
if( $retval === 0 ) {
// the syntax is good
rename( "newfile.php", "functions.php");
}
You would need to set the appropriate paths for this to work.
Now all of that said, this is not a very good idea and I would advise you not to implement it. A better method would be to break your functions out into separate files. Then use an INI config file or a database to keep track of what you should load. Either of those have the ability to be edited. Even a text data file would be better than mucking with the actual code.
Once you know what you're supposed to load then at the beginning require or include the appropriate file.
Here's a simple example of doing it with a database:
$res = mysql_query("SELECT file_name FROM load_functions");
if( mysql_error() ) {
// do something because the query failed
}
else {
while( list($file_name) = mysql_fetch_row($res) ) {
if( file_exists($file_name) ) {
require_once( $file_name );
}
else {
// warn because a file requested didn't exist
}
}
}
Hope that helps
Ok for sure this has been asked and answered already but i somehow can't find a proper tutorial.
I want to keep the text displayed to users somewhere else and to prevent my code from becoming too large and unreadable.
My site won't be internationalized. I just want to have some kind of file with key-value structure and get the text from there. I want to keep the text in files, not in the database as some tutorials suggest.
I found a solution which will work but i am not sure whether this is a good approach.
I am thinking of using parse_ini_file and to keep my texts in .ini file. Is there something wrong with this approach? Could you suggest something better?
I put all language data in arrays. Its easy and also we can add multi-language support
lang/en.php
<?php
return array(
'index' => 'Homepage',
'feedback' => 'Feedback'
'logout' => 'Logout from profile',
)
?>
lang/ru.php
<?php
return array(
'logout' => 'Выйти из профиля',
)
?>
Then we can load languages:
$lang = include('lang/en.php');
if(isset($_GET['lang']))
{
$lang = array_merge($lang, include('lang/ru.php'));
}
After all it $lang will look like:
Array
(
[index] => Homepage
[feedback] => Feedback
[logout] => Выйти из профиля
)
And we can very simple use it:
function __($name) {
global $lang;
return $lang[$name];
}
Somewhere in the site template:
...
<title><?=__('index')?></title>
</head>
<body>
<?=__('feedback')?>
why not use a plain text file with commas or some uncommon character to hold this data? you can read it and parse it into an array with
$file = file_get_contents("/path/to/file");
$lines = explode('\r', $file);
foreach($lines as $line) $message[substr($line, 0, strpos($line, ','))] = substr($line, strpos($line, ','));
then you should have an array like $messages[3] = "No soup for you!";
the file might look like:
1,The site is down.
2,Try again.
3,No soup for you!
4,Signs point to yes.
(I probably have some of the arguments misplaced in those functions - i always forget which is the needle and which the haystack.)
You can process your data in a script. In this script, you call a certain source (e.g. the ini file you suggest). Then you use a template engine. For this engine, you point towards a template file and give the template all the variables.
The template generates the html and inserts the variables at the right place. This way, you keep you php (business logic) code clean, away from the presentation (the template). Also you can manage the variables in one file (ini/xml but this can be something completely different).
For template engines, Smarty is the most known of all. There are also pure php-based template systems, just Google for them to find one that suits your needs.
I do like this:
$defaultLang = array('Home','Logout',etc)
$otherLang=array( 'ru' => array('Home_in_ru','logout_in_ru',etc);
you translate like this:
echo translate('Home');
function is:
function translate($msg) {
if ($_GET['lang']=='en')
return $msg;
return $otherLang[$_GET['lang']][array_search($msg,$defaultLang)];
}
// Note the function is simplified up there
As you can see the default case deosnt' need to load anything or do any operation, the function just returns back the argument passed
i like the answer with the lang/en.php file. but instead of a file for each language, i use a file for each web page (or class, etc). this keeps file sizes lower and i create a 3D array:
`return array( "EN" => array( "title" => "Welcome - Good Morning", ...),
"TG" => array( "title" => "Mabuhay - Magandang Umaga Po", ...)
);'
Real easy to add new language strings too...
This makes it real easy for language translation contractors since they can see the native language in close proximity to the foreign in 1 editor,,,
I would like to programatically (using php) fill out an existing drupal form to create a content type that is included in a contributed module.
Details: The module is SimpleFeed and the content type is Feed. I would like to call the module's functions to accomplish this. The method I am interested in is hook_insert which appears to require vid and nid which I am unsure what these are.
Any help is appreciated.
can you provide a bit more information (which modules?). generally, i'd probably suggest calling the modules functions to create the content type, instead of trying to pass it through a form programatically. this way you don't have to worry about implementation, and can trust that if the module works, it'll work for your script too :)
of course this does tie your module to theirs, so any changes in their functions could affect yours. (but then again, you run that risk if they update their database structure too)
ex.
// your file.php
function mymodule_do_stuff() {
cck_create_field('something'); // as an example, i doubt this
// is a real CCK function :)
}
edit: vid and nid are node ID's, vid is the revision id, and nid is the primary key of a particular node. because this is an actual node, you may have to do two operations.
programatically create a node
you'll have to reference the database for all the exact fields (tables node and node_revisions), but this should get you a basic working node:
$node = (object) array(
'nid' => '', // empty nid will force a new node to be created
'vid' => '',
'type' => 'simplefeed'. // or whatever this node is actually called
'title' => 'title of node',
'uid' => 1, // your user id
'status' => 1, // make it active
'body' => 'actual content',
'format' => 1,
// these next 3 fields are the simplefeed ones
'url' => 'simplefeed url',
'expires' => 'whatever value',
'refresh' => 'ditto',
);
node_save($node);
now i think it should automatically call simplefeed's hook_insert() at this point. if not, then go on to 2. but i'd check to see if it worked out already.
call it yourself!
simplefeed_insert($node);
edit2: drupal_execute() isn't a bad idea either, as you can get back some validation, but this way you don't have to deal with the forms API if you're not comfortable with it. i'm pretty sure node_save() invokes all hooks anyhow, so you should really only have to do step 1 under this method.
The drupal api provides drupal_execute() to do exactly this. I would suggest you avoid calling the functions directly to create the node (unless there is a performance reason). By using drupal_execute() all the proper hooks in other modules will be called and your code is far more likely to continue to work through future versions of drupal.
Note that a classic bug in using this method is not first calling something like
module_load_include('inc', 'node', 'node.pages')
which will load the code for your node creation form.
Calling node_save directly is generally considered deprecated and could leave you with broken code in future versions of drupal.
There is a nice example at this lullabot post