I have a TV named "Kategorie" and I want a list of all resources underneath a specified resource (27) grouped by this TV. Nothing special imho. This is my approach:
<?php
$resource_ids = $modx->getTree(27,1); # => 27 is the Container with the desired resources
# We need the 'Kategorie'-TV of the resources
$cat = $modx->getObject('modTemplateVar', array('name' => 'Kategorie'));
# Map Resources to Category
$resources_by_cat = array();
foreach ($resource_ids as $id) {
$resources_by_cat[$cat->getValue($id)][] = $id;
}
# Iterate over categories and output the resources
foreach ($resources_by_cat as $cat => $ids) {
$joined_ids = join(",",$ids); # => eg "33,34,56"
print "<h2>".$cat."</h2>";
print '<table class="references">';
print '
<tr>
<th class="title">Titel</th>
<th class="author">Von</th>
</tr>
';
print $modx->runSnippet('getResources', array(
"resources" => $joined_ids,
"includeTVs" => "1",
"tpl" => "referenceRow"
));
print '</table>';
}
?>
… which looks fine to me but throws this error to me:
[2011-01-05 12:26:24] (ERROR # /index.php) Error 42000 executing statement: Array ( [0] => 42000 [1] => 1064 [2] => You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '1,2,15,18,27,23,30,3,4,22,24,26,47,5,6,7,8,9,10,11,12,14,13,17,16,19,20,49,50,21' at line 1 )
Anyone knows what's going on here? Or is there even a better approach to my goal?
UPDATE
I updated to the most recent version of getResources. Now I don't get that error message. Yet it does not work. But the "parents" option does not work either.
I used $modx->getDocument($id) instead and it works now as expected.
foreach($ids as $rid) {
$doc = $modx->getDocument($rid);
var_dump($doc);
// real output trimmed
}
Related
This is my first time working with either PHP or SQL.
I'm making a simple website which hosts apps alongside their names, authors, version, descriptions etc. The PHP script fetches this information from a MySQL database I've made. Each app has a unique identifier assigned to it. Multiple versions would re-use the same identifier.
I've got it to display the entries with only one version fine.
However...
When an updated version of an app is released, I want it to list the old version(s) (just the version number linked to the old version's link) in a drop down next to the newest version. I made the database assuming that I'd figure out a way to display it fine, thus when I added an updated version of an app to the database, I left the things that didn't change blank (like name, author, description), gave it the same identifier as the older version and only added the newer version number and the filename of the newer version. See here for an example.
However, I assumed wrong.
I have no clue how to proceed. I have a query:
SELECT * FROM apps WHERE identifier IN ( SELECT identifier FROM apps GROUP BY identifier HAVING count(*) > 1)
However, this only selects all of the entries which have duplicate "identifier"s. I don't know how to run this through a loop, to echo the older entry's description/name but the newer entry's version number/link (while ALSO being able to echo the old version number/link for my dropdown). Oh, and also so it wouldn't assign names/descriptions/etc to apps which DO have a duplicate identifier, but which isn't identical to other apps' identifiers. Sorry, this is hard to explain.
My current loop, which is:
$result=mysqli_query($connection,$query);
$num=mysqli_num_rows($result);
$i=0;while ($i < $num) {while ($row = mysqli_fetch_array($result)) {
// do stuff (echo)
} ;$i++;};
just echoes the entries seperately, one being the old version and one being the new version (with no description, name or author displayed).
How should I proceed?
How about something like this:
You select all the data from your table, ordered by identifier and then by version. The query being something like:
-- ↓ orders data by identifier, thereby 'grouping' together records with the same identifier
SELECT * FROM apps ORDER BY identifier, version DESC
-- ↑ orders each 'group' by version number descending - highest / 'newest' first
Then, from this data, you could create an array structure in PHP which would enable you to easily loop through the data. Something like the following:
$result = mysqli_query($connection,$query);
$apps = array(); // Create apps array
while ($row = mysqli_fetch_array($result)) {
// Assign the Name, Description, Author of the row
// These will be blank until the last (oldest version) which has these values
// $app[$row[1]] will create a key for each identifier or use the existing one
$apps[$row[1]]["name"] = $row[2];
$apps[$row[1]]["description"] = $row[3];
$apps[$row[1]]["author"] = $row[4];
// If there is no current version stored
if(empty($apps[$row[1]]["current_version"])){
$apps[$row[1]]["current_version"]["version"] = $row[5];
$apps[$row[1]]["current_version"]["source"] = $row[6];
$apps[$row[1]]["current_version"]["filename"] = $row[7];
} else { // If not, this means this row is an older version
$v = array(
"version" => $row[5],
"source" => $row[6],
"filename" => $row[7],
);
$apps[$row[1]]["older_versions"][] = $v; // Add the array to the older_versions array
}
}
This then produces the following array structure:
Array
(
[vitashell] => Array
(
[name] => VitaShell
[description] => VitaShell is an alternative replacement...
[author] => TheFloW
[current_version] => Array
(
[version] => 0.86
[source] => http://www.example.com/link/version/0_86
[filename] => vitashell_0_86.vpk
)
[older_versions] => Array
(
[0] => Array
(
[version] => 0.8
[source] => http://www.example.com/link/version/0_8
[filename] => vitashell_0_8.vpk
)
)
)
[identifier] => Array (...)
)
You could then use a couple of foreach loops to go through the $apps array printing out the data as necessary.
I made a simple example of printing out the data. For display purposes, I added some dummy rows to the dataset:
<?php foreach($apps as $app){ ?>
<div class="app">
Name: <?php echo $app["name"]; ?><br />
Description: <?php echo $app["description"]; ?> <br />
Author: <?php echo $app["author"]; ?> <br />
Version: <?php echo $app["current_version"]["version"]; ?> <br />
<?php if(!empty($app["older_versions"])){ ?>
Older Versions:
<select name="older_versions">
<?php foreach($app["older_versions"] as $version){ ?>
<option value="<?php echo $version["source"] ?>"><?php echo $version["version"]; ?></option>
<?php } ?>
</select>
<?php } ?>
</div>
<hr>
<?php } ?>
Which creates:
Note: "TIMSTUFF" only has 1 version, hence no drop-down for older versions
This question already has answers here:
Scrape web page data generated by javascript
(2 answers)
Closed 8 years ago.
I am stuck with a scraping task in my project.
i want to grab the data from the link in $html , all table content of tr and td , here i am trying to grab the link but it only shows javascript: self.close()
<?php
include("simple_html_dom.php");
$html = file_get_html('http://www.areacodelocations.info/allcities.php?ac=201');
foreach($html->find('a') as $element)
echo $element->href . '<br>';
?>
Usually, this kind of pages load a bunch of Javascript (jQuery, etc.), which then builds the interface and retrieves the data to be displayed from a data source.
So what you need to do is open that page in Firefox or similar, with a tool such as Firebug in order to see what requests are actually being done. If you're lucky, you will find it directly in the list of XHR requests. As in this case:
http://www.govliquidation.com/json/buyer_ux/salescalendar.js
Notice that this course of action may infringe on some license or terms of use. Clear this with the webmaster/data source/copyright owner before proceeding: detecting and forbidding this kind of scraping is very easy, and identifying you is probably only slightly less so.
Anyway, if you issue the same call in PHP, you can directly scrape the data (provided there is no session/authentication issue, as seems the case here) with very simple code:
<?php
$url = "http://www.govliquidation.com/json/buyer_ux/salescalendar.js";
$json = file_get_contents($url);
$data = json_decode($json);
?>
This yields a data object that you can inspect and convert in CSV by simple looping.
stdClass Object
(
[result] => stdClass Object
(
[events] => Array
(
[0] => stdClass Object
(
[yahoo_dur] => 11300
[closing_today] => 0
[language_code] => en
[mixed_id] => 9297
[event_id] => 9297
[close_meridian] => PM
[commercial_sale_flag] => 0
[close_time] => 01/06/2014
[award_time_unixtime] => 1389070800
[category] => Tires, Parts & Components
[open_time_unixtime] => 1388638800
[yahoo_date] => 20140102T000000Z
[open_time] => 01/02/2014
[event_close_time] => 2014-01-06 17:00:00
[display_event_id] => 9297
[type_code] => X3
[title] => Truck Drive Axles # Killeen, TX
[special_flag] => 1
[demil_flag] => 0
[google_close] => 20140106
[event_open_time] => 2014-01-02 00:00:00
[google_open] => 20140102
[third_party_url] =>
[bid_package_flag] => 0
[is_open] => 1
[fda_count] => 0
[close_time_unixtime] => 1389045600
You retrieve $data->result->events, use fputcsv() on its items converted to array form, and Bob's your uncle.
In the case of the second site, you have a table with several TR elements, and you want to catch the first two TD children of each TR.
By inspecting the source code you see something like this:
<tr>
<td> Allendale</td>
<td> Eastern Time
</td>
</tr>
<tr>
<td> Alpine</td>
<td> Eastern Time
</td>
So you just grab all the TR's
<?php
include("simple_html_dom.php");
$html = file_get_html('http://www.areacodelocations.info/allcities.php?ac=201');
$fp = fopen('output.csv', 'w');
if (!$fp) die("Cannot open output CSV - permission problems maybe?");
foreach($html->find('tr') as $tr) {
$csv = array(); // Start empty. A new CSV row for each TR.
// Now find the TD children of $tr. They will make up a row.
foreach($tr->find('td') as $td) {
// Get TD's innertext, but
$csv[] = $td->innertext;
}
fputcsv($fp, $csv);
}
fclose($fp);
?>
You will notice that the CSV text is "dirty". That is because the actual text is:
<td> Alpine</td>
<td> Eastern Time[CARRIAGE RETURN HERE]
</td>
So to have "Alpine" and "Eastern Time", you have to replace
$csv[] = $td->innertext;
with something like
$csv[] = strip(
html_entity_decode (
$td->innertext,
ENT_COMPAT | ENT_HTML401,
'UTF-8'
)
);
Check out the PHP man page for html_entity_decode() about character set encoding and entity handling. The above ought to work -- and an ought and fifty cents will get you a cup of coffee :-)
I am using "simple_html_dom.php" to scrap the data from the Wikipedia site. If I run the code in scraperwiki.com it's throwing an error as exit status 139 and if run the same code in my xampp sever, the server is hanging.
I have a set of links
I'm trying to get Literacy value from all the sites
If I run the code with one link there is no problem and it's returning the expected result
If I try to get data from all the sites in one go I'm facing the above problem
The code is:
<?php
$test=array
(
0 => "http://en.wikipedia.org/wiki/Andhra_Pradesh",
1 => "http://en.wikipedia.org/wiki/Arunachal_Pradesh",
2 => "http://en.wikipedia.org/wiki/Assam",
3 => "http://en.wikipedia.org/wiki/Bihar",
4 => "http://en.wikipedia.org/wiki/Chhattisgarh",
5 => "http://en.wikipedia.org/wiki/Goa",
for($ix=0;$ix<=9;$ix++){
$content = file_get_html($test[$ix]);
$tables = $content ->find('#mw-content-text table',0);
foreach ($tables ->children() as $child1) {
foreach($child1->find('th a') as $ele){
if($ele->innertext=="Literacy"){
foreach($child1->find('td') as $ele1){
echo $ele1->innertext;
}}} }}
Guide me where am wrong. Is there any memory problem??? Is there any xampp configuration???
<?php
require 'simple_html_dom.php';
$test = array(
0 => "http://en.wikipedia.org/wiki/Andhra_Pradesh",
1 => "http://en.wikipedia.org/wiki/Arunachal_Pradesh",
2 => "http://en.wikipedia.org/wiki/Assam",
3 => "http://en.wikipedia.org/wiki/Bihar",
4 => "http://en.wikipedia.org/wiki/Chhattisgarh",
5 => "http://en.wikipedia.org/wiki/Goa");
for($ix=0;$ix<=count($test);$ix++){
$content = file_get_html($test[$ix]);
$tables = $content ->find('#mw-content-text table',0);
foreach ($tables ->children() as $child1) {
foreach($child1->find('th a') as $ele){
if($ele->innertext=="Literacy"){
foreach($child1->find('td') as $ele1){
echo $ele1->innertext;
}
}
}
}
$content->clear();
}
?>
but these URLs are too much. You may get a fatal error of max execution time execeeded or you may get error 324.
In my PHP script I run an update statement as follows:
$this->_db->update('names', $data, $this->_db->quoteInto('id = ?', $obj->id));
The db handle is a Zend_Db_Adapter_Abstract instance (of the PDO MySql variety).
The problem is that the update is failing and I can't seem to get more info on the error.
The error occurs within a try/catch block. When I catch the error, I run:
$db->getProfiler()->getLastQueryProfile();
And the output is:
2012-11-14T22:20:02+11:00 INFO (6): Zend_Db_Profiler_Query Object
(
[_query:protected] => begin
[_queryType:protected] => 64
[_startedMicrotime:protected] => 1352892002.6064
[_endedMicrotime:protected] => 1352892002.6066
[_boundParams:protected] => Array
(
)
I know it says no parameters are bound, but I really don't think that's the case. I think that somehow 'last query' is not what I think it is.
Secondly, when I catch the error I also run:
$db->getConnection()->errorInfo();
And the output is:
2012-11-14T22:20:02+11:00 INFO (6): Array
(
[0] => 00000
[1] =>
[2] =>
)
Obviously this is not very helpful.
Any ideas? How can I get more info on the error?
Thanks!
You can force PDO to throw exceptions with all the info:
<?php
$this->_db->->getConnection()->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
try {
$this->_db->update('names', $data, $this->_db->quoteInto('id = ?', $obj->id));
}
catch (Exception $ex) {
print_r($ex);
}
I have this sphinx search engine that I use through Zend using sphinxapi.php . It works fantastic. Really really great.
However, there is one problem: It randomly fails.
// Prepare Sphinx search
$sphinxClient = new SphinxClient();
$sphinxClient->SetServer($ip, $port);
$sphinxClient->SetConnectTimeout( 10 );
$sphinxClient->SetMatchMode( SPH_MATCH_ANY );
$sphinxClient->SetLimits( $resultsPerPage * ($nPage - 1), $resultsPerPage );
$sphinxClient->SetArrayResult( true );
$query = array();
$query['lang'] = '#lang "lang' . $language . '"';
if (isset($params)) {
foreach ($params as $param) {
$query['tags'] = '#tags "' . $param . '"';
}
}
// Make the Sphinx search
$sphinxClient->SetMatchMode(SPH_MATCH_EXTENDED);
$sphinxResult = $sphinxClient->Query(implode(' ', $query), '*');
As seen here, I search for a language and an arbitrary amount of tags, imploded into a single query string in the end (instead of making a battleload of subqueries).
So, normally, this works like a charm, but occassionally sphinx returns that it found 2000 entries in English and, say, 1000 entries with the tag "pictures" (or some other purely english word) but ZERO hits that fit both results, which is purely false. In fact, refreshing the page everything returns to normal with something like 800 real results.
My question is why does it do this and how do I make it stop?
Any ideas?
:Edit: Added shortened output log
[error] =>
[warning] =>
...
[total] => 0
[total_found] => 0
[time] => 0.000
[words] => Array (
[langen] => Array (
[docs] => 2700
[hits] => 2701 )
[picture] => Array (
[docs] => 829
[hits] => 1571 ) ) )
have you checked to see if the sphinx client is giving you any error or warning messages that may describe the failure?
if($sphinxResult === false) {
print "Query failed: " . $sphinxClient->GetLastError();
} else {
if($sphinxClient->GetLastWarning()) {
print "WARNING: " . $sphinxClient->GetLastWarning();
}
// process results
}
This issue has been solved completely a few months after the original post. The issue is that our service providers in the umbrella corporation har mistakenly assigned the wrong root values to the sphinx commands. The problem above was actually running on Sphinx 0.9.8 and was obviously buggy. My advice, if you ever experience similar problems is to double-tripple-check the version you use both to index and to query.
It feels like one of those times your math calculation doesn't roll out because you forgot a minus on the first row. Thanks to everyone that have tried to help in this and related threads.