AnsweredAssumed Answered

Submitting BbLearn forms with PHP

Question asked by hanleybrand on Nov 22, 2017
Latest reply on Nov 22, 2017 by hanleybrand

In the past couple months I've tried to write tools in PHP that would automate creating course archives and downloading a course's grade center to be used from our home grown course management dashboard (at Temple Faculty setup the creation & enrollment of their own courses from SIS data using a tool we deployed in like 2000 (obvs it's been updated a number of times)).


When I was trying to sell my co-workers on switching to Django, I was able to do the grade center one without too much time spent:


   ## s = a requests.session obj already logged in as a user with admin rights

    dl_step1_path = 'webapps/gradebook/do/instructor/downloadGradebook?dispatch=viewDownloadOptions&course_id='
    dl_step2_path = 'webapps/gradebook/do/instructor/downloadGradebook?dispatch=executeDownload'

    # get the downloadGradebookForm so options can be set (as far as I can tell, necessary because nonce)
    step1 = s.get(join_url(server_url, dl_step1_path, cid))

    # use BS4 to make sure all the form fields are gotten so the post is correct
    soup = BeautifulSoup(step1.text, 'html.parser' )
    form = soup.find('form', attrs={'name': 'downloadGradebookForm'})
    inputs = {element['name']: element['value'] for element in form.find_all('input')}

    for key in dl_set:
        inputs[key] = dl_set[key]

    p =, dl_step2_path), data=inputs, stream=True)

    # get the file name from the Content-Disposition header
    f_value, f_params = cgi.parse_header(p.headers['Content-Disposition'])

    dirname = path(__file__).abspath().dirname()
    filename = dirname / csv_path / f_params['filename']
    # print filename.abspath()

    with open(filename.abspath(), 'wb') as f:


But while PHP is different, it seemed like the basic steps should be the same:



// $goutte = a Goutte\Client object that's been logged in successfully with admin rights
$bb_tld = "";
$dl_gradbook_path = "webapps/gradebook/do/instructor/downloadGradebook";
$dl_step1_end = "?dispatch=viewDownloadOptions&course_id=$course_pk1";
$dl_step2_end = "?dispatch=executeDownload";

$dl_step1_url = $bb_tld . $dl_gradbook_path . $dl_step1_end;

$step1_req = $goutte->request('GET', $dl_step1_url);
// here's what makes the annoyances of goutte worth it - the last expression created 
// a DomCrawler object (which is weird, but I see the appeal) which makes it easy to get the form
$form = $step1_req->selectButton('bottom_Submit')->form();

// in my case, I want the defaults of the form --
// I could use  $form->setValues([param_array]) to change them
// I used $form->getPhpValues() to confirm the defaults are correct
// so submit the form to get the download link
$step2_page = $goutte->submit($form);

// ok, step 2 (the page with the download link) 
$data_con = $step2_page->filter('#containerdiv');
$form2 = $step2_page->filter('#download_form')->form();

// get the values (specifically item) for a unique temp file name
$fields2 = $form2->getPhpValues();
$tmp_file_name = $fields2['course_id'] . '_' . $fields2['item'] . '.tsv';

// so this should submit the frm as if someone clicked on the pseudo-button
// but the response is an error
$dl_tsv_file = $goutte->submit($form);
$tsv_download_response = $goutte->getResponse()->getContent();

// this doesn't happen, but I think it won't work exactly as is because whatever (streams, etc, idk)
$directory_path = './tmp/';
$file = new SplFileObject($directory_path . $tmp_file_name , 'w');


But the last step results in a Bb Error Page:


Access Denied

Content Access Denied

Either you are not logged in or you do not have the appropriate privileges to perform this action. You may have access to other parts of the course.

Wednesday, November 22, 2017 1:26:35 PM EST matter what I've tried (I've already rewritten this twice thinking things like maybe guzzle is better than goutte, etc.)


Any chance anyone here has figured this particular problem out? It's a little embarrassing because I told my boss on Monday that it would be "real quick" and here it is Wednesday afternoon and I guess I'm still at "real quick" when comparing speed to say, an ocean liner journey across the Atlantic or something.